CVE-2022-44268漏洞分析
CVE-2022-44268漏洞分析
漏洞描述
ImageMagick 7.1.0-49 is vulnerable to Information Disclosure. When it parses a PNG image (e.g., for resize), the resulting image could have embedded the content of an arbitrary file (if the magick binary has permissions to read it).
漏洞环境
漏洞复现
安装依赖
1 | pip install pypng |
使用poc.py生成poc
1 | python poc.py generate -o poc.png -r /etc/passwd |
上传文件并保存新生成的图片为out.png
使用poc.py提取文件信息
1 | python poc.py parse -i out.png |
PNG组成
最好结合010Editor进行分析
PNG数据块
PNG定义了两种数据块,分别为关键数据块和辅助数据块
数据块符号 | 数据块名称 | 多数据块 | 可选否 | 位置限制 |
---|---|---|---|---|
IHDR | 文件头数据块 | 否 | 否 | 第一块 |
cHRM | 基色和白色点数据块 | 否 | 是 | 在PLTE和IDAT之前 |
gAMA | 图像γ数据块 | 否 | 是 | 在PLTE和IDAT之前 |
sBIT | 样本有效位数据块 | 否 | 是 | 在PLTE和IDAT之前 |
PLTE | 调色板数据块 | 否 | 是 | 在IDAT之前 |
bKGD | 背景颜色数据块 | 否 | 是 | 在PLTE之后IDAT之前 |
hIST | 图像直方图数据块 | 否 | 是 | 在PLTE之后IDAT之前 |
tRNS | 图像透明数据块 | 否 | 是 | 在PLTE之后IDAT之前 |
oFFs | (专用公共数据块) | 否 | 是 | 在IDAT之前 |
pHYs | 物理像素尺寸数据块 | 否 | 是 | 在IDAT之前 |
sCAL | (专用公共数据块) | 否 | 是 | 在IDAT之前 |
IDAT | 图像数据块 | 是 | 否 | 与其他IDAT连续 |
tIME | 图像最后修改时间数据块 | 否 | 是 | 无限制 |
tEXt | 文本信息数据块 | 是 | 是 | 无限制 |
zTXt | 压缩文本数据块 | 是 | 是 | 无限制 |
fRAc | (专用公共数据块) | 是 | 是 | 无限制 |
gIFg | (专用公共数据块) | 是 | 是 | 无限制 |
gIFt | (专用公共数据块) | 是 | 是 | 无限制 |
gIFx | (专用公共数据块) | 是 | 是 | 无限制 |
IEND | 图像结束数据 | 否 | 否 | 最后一个数据块 |
数据块中有 4 个关键数据块,其中 IHDR、IDAT 和 IEND 是必填选项:
- 文件头数据块 IHDR(header chunk):包含有图像基本信息,作为第一个数据块出现并只出现一次。
- 调色板数据块 PLTE(palette chunk):必须放在图像数据块之前。
- 图像数据块 IDAT(image data chunk):存储实际图像数据。PNG 数据允许包含多个连续的图像数据块。
- 图像结束数据 IEND(image trailer chunk):放在文件尾部,表示 PNG 数据流结束。
数据块结构
PNG文件中,每个数据块由4个部分组成,如下:
名称 | 字节数 | 说明 |
---|---|---|
Length(长度) | 4字节 | 指定数据块中数据域的长度,其长度不超过(231-1)字节。该长度只包含数据块的长度。 |
Chunk Type Code(数据块类型码) | 4字节 | 数据块类型码由ASCII字母(A-Z和a-z)组成 |
Chunk Data(数据块数据) | 可变长度 | 存储按照Chunk Type Code指定的数据 |
CRC(循环冗余检测) | 4字节 | 存储用来检测是否有错误的循环冗余码 |
PNG标识符
PNG格式固定标识头是89504E47 0D0A1A0A
TIPS
此处漏洞出现的位置位于tEXt
数据块
漏洞分析
从补丁看到漏洞出现在ReadOnePNGImage()
函数,在使用ImageMagick命令转换png文件时会触发该函数
https://github.com/ImageMagick/ImageMagick/blob/7.1.0-49/coders/png.c#L2164
找到打补丁的地方,是ImageMagick在处理MagickPathExtent
的时候,根据源码可以知道FormatLocaleString()
用于将一个变量列表转换为字符串,SetImageProperty()
用于将指定的字符串赋值给特定的已知属性或自由属性
https://github.com/ImageMagick/ImageMagick/blob/7.1.0-49/coders/png.c#L3982
跟进SetImageProperty()
https://github.com/ImageMagick/ImageMagick/blob/7.1.0-49/MagickCore/property.c#L4360
在处理profile
属性时候,会将指定的文件转换成字符串赋值回profile
,随后重新将profile
的值设置回图片中
https://github.com/ImageMagick/ImageMagick/blob/7.1.0-49/MagickCore/property.c#L4711
跟进FileToStringInfo()
,从源码得知该函数用于返回指定文件的内容,所以造成了信息泄漏漏洞
https://github.com/ImageMagick/ImageMagick/blob/7.1.0-49/MagickCore/string.c#L1005
补丁
https://github.com/ImageMagick/ImageMagick/commit/05673e63c919e61ffa1107804d1138c46547a475