在说这个漏洞本身之前,记录下发现这个问题的整个流程
首先是unsafe-inline下绕过本身的意义
大家都知道location可以直接泄露出数据,但是,也只能是单向发送罢了。
并没有在开启csp的域下,加载外部的资源
很多公司的的真实案例
a.com是一个站点,允许和子域间的通信
如果子域x.a.com 产生了一个xss,原本就可以通过iframe加载a.com 直接获取其cookie
但是,这时候a.com不在x.a.com的CSP列表里,这个iframe的请求会被拦截
这时候如果'完整的'绕过了unsafe-inline 这个攻击就可以正常进行了
而这似乎是单纯的数据泄露类绕过所做不到的(location,link prefetch)
而下面,就讲一讲,能够在本身域下绕过CSP的方法,也就是通过CSP的继承问题来进行绕过。
CSP的继承问题很早就有了
比如a.com整站启用了CSP,然而有一处a.com/nocsp.html没有开启
在Chrome 58以前,可以通过同源操作的方法来绕过
<iframe src=nocsp.html id=”x” />
<script>
x.contentDocument.write(“<img src='attacker.com' />”);
</script>
这当然是个很大的问题,如果整个域下有一个地方没有开启CSP,那么CSP就失去了效果。
在CVE-2017-5033指出
对于本地的伪协议,如about:blank,它并没有继承CSP
<iframe src=”about:blank” id=”x” />
<script>
x.contentDocument.write(“<img src='attacker.com' />”);
</script>
对于这样的一个漏洞,首先定位到它所在的代码。
/third_party/WebKit/Source/core/dom/Document.cpp
对于window.open() 打开的链接,都直接继承了其window.opener的CSP策略
但是iframe里的逻辑和window.open还不太一样,审计其修复源码
void Document::InitContentSecurityPolicy 函数
if (url_.IsEmpty() || url_.ProtocolIsAbout() || url_.ProtocolIsData() ||
url_.ProtocolIs("blob") || url_.ProtocolIs("filesystem")) {
GetContentSecurityPolicy()->CopyStateFrom(policy_to_inherit);
发现对于iframe,过滤了如下本地协议
blob,data,filesystem,about
但是... 残留下了一个最常见的伪协议
javascript: 伪协议
我2015年的blog里发现了这个特性
https://www.math1as.com/index.php/archives/145/
如果表达式中有类似 "<b>"+"1"+"</b>" 这种可以解释为合法表达式的字符串,那么它们会被解析成html执行
于是.. 如果我们使用javascript:伪协议注入html呢?
其实,javascript:本身继承了其加载域,也可以使用同源操作。
但是最简单的方法,还是直接嵌套一层
<iframe src=”javascript:'<iframe src=attacker.com \/>'”
再次Bypass了CSP