SORA.SEC WIRED ARCHIVE 网络安全
581 字
3 分钟
CVE-2025-64512分析

CVE

CVE-2025-64512分析,从PDF对象树到RCE#

捉襟见肘,对于pdf安全问题,直接的pdf是没有什么威胁的,造就一个事物有没有威胁要看自己的原生库是

怎么对其进行加载的。接下来会说明一些有关PDF的数据结构

整个PDF的结构可以类似于一个对象树,很多时候可以相互引用

比如说入口是

1 0 obj
<<
/Type /Catalog
/Pages 2 0 R
>>
endobj

这里就是1对象,并且说明了/Page的值位于2对象,后面跟的0代表版本,这个版本多数是用于pdf更新之后

的引用

5 0 obj
<<
/Type /Font
/Subtype /Type1
/BaseFont /Helvetica
>>
endobj

字体对象,如果说要引用,那就在其他对象引用对象5

因为对于对象嵌套,数据流压缩,对象流压缩的宽容度很大,这里看python的pdfminer对于其的处理

看看在pdfminer的前些版本,对于字体的Cmap处理

Cmap是映射表,当发现对于/Encoding的值,是可以当作路径去load的,看看逻辑

def _load_data(cls, name: str) -> Any:
name = name.replace("\0", "")
filename = "%s.pickle.gz" % name
log.debug("loading: %r", name)
cmap_paths = (
os.environ.get("CMAP_PATH", "/usr/share/pdfminer/"),
os.path.join(os.path.dirname(__file__), "cmap"),
)
for directory in cmap_paths:
path = os.path.join(directory, filename)
if os.path.exists(path):
gzfile = gzip.open(path)
try:
return type(str(name), (), pickle.loads(gzfile.read()))
finally:
gzfile.close()
raise CMapDB.CMapNotFound(name)

可以看出cmap_paths是可信的,在environ,但是filename貌似是直接拼字段,追溯下

def get_cmap_from_spec(self, spec: Mapping[str, Any], strict: bool) -> CMapBase:
"""Get cmap from font specification
For certain PDFs, Encoding Type isn't mentioned as an attribute of
Encoding but as an attribute of CMapName, where CMapName is an
attribute of spec['Encoding'].
The horizontal/vertical modes are mentioned with different name
such as 'DLIdent-H/V','OneByteIdentityH/V','Identity-H/V'.
"""
cmap_name = self._get_cmap_name(spec, strict)
try:
return CMapDB.get_cmap(cmap_name)
except CMapDB.CMapNotFound as e:
if strict:
raise PDFFontError(e)
return CMap()

cmap_name也就是name的规范化

def _get_cmap_name(spec: Mapping[str, Any], strict: bool) -> str:
"""Get cmap name from font specification"""
cmap_name = "unknown" # default value
try:
spec_encoding = spec["Encoding"]
if hasattr(spec_encoding, "name"):
cmap_name = literal_name(spec["Encoding"])
else:
cmap_name = literal_name(spec_encoding["CMapName"])
except KeyError:
if strict:
raise PDFFontError("Encoding is unspecified")
if type(cmap_name) is PDFStream: # type: ignore[comparison-overlap]
cmap_name_stream: PDFStream = cast(PDFStream, cmap_name)
if "CMapName" in cmap_name_stream:
cmap_name = cmap_name_stream.get("CMapName").name
elif strict:
raise PDFFontError("CMapName unspecified for encoding")
return IDENTITY_ENCODER.get(cmap_name, cmap_name)

对于encoding的值,可以看看对于其的取值逻辑

其中name就是传入的/Encoding 的值,这两个分支分别代表了原始对象以及复合对象,

并且spec是在最开始PDF进入时就init加载的,于是便可以进行代码执行了

以上

CVE-2025-64512分析
https://ymsora.com/posts/pdf1/
作者
YMsora~X
发布于
2026-07-21
许可协议
Unlicensed
LAST UPDATE / 最后更新