用css绕过同源策略跨域窃取数据
如果你和我一样无聊,你可能遇到过这种潜在的攻击 -》https://www.w3.org/TR/CSP2/#security-css-parsing
如果浏览器使用了一种宽松的css解析方法来渲染,攻击者可能通过插入非同源且非法的脚本来窃取用户的数据
和遇到语法错误就会停止运行的JavaScript相比,css解析规则会在遇到语法错误的情况下忽略那些不合语法的部分
2009年的时候, Chris Evans发现了一种跨域窃取的方法。他的思路是,找一个可以反射get参数的页面,将自己的payload注入在页面里然后把它引入到一个自己可控服务器上的页面里。简单的解释如下图
简单的来说,就是攻击者注入了2处payload,第一处是
{}#f{font-family:'
第二处是
';}
这两者把数据包围起来,划删除线的地方我们可以忽略掉,然后中间的user对象的这些数据就编程了一个font-family属性的值,即单引号内的,所 以这也将成为一个前置条件,那就是要窃取的数据中不能同时出现单双引号。现在,我们可以通过getComputedStyle方法来获取font- family的值了,而这个值将包含user对象中的数据 :)。 我们可以看到,我们注入的数据其实没有很明显的恶意特征(比如脚本标记”<“,”>”),所以通常来说它们并不会被escape。最后我们就 可以通过这样的方式完成跨域窃取敏感信息,数据甚至可能包含csrf所需的token,或者更敏感的个人信息。
攻击的一些前提约束
这些条件在现代的编码风格下是很难遇到,尤其是不允许出现换行。
IE和Firefox禁止了一个不正确的MIME类型(text/css)的跨域加载。另方面,基于webkit的浏览器为了兼容性原因使用strict模式来加载跨域的css文件,这些webkit浏览器采用的方法其实也是csp2官方所建议的。
所有的浏览器应该具有一种更严格的css解析规则来防御错误MIME tyle导致的跨域问题。
这个防御 建议看起来是一种完美的平衡:它解决了能够在不破坏已经使用了错误类型的MIME type网站的前提下更好的处理和防御这种跨域攻击的问题。它可以不破坏那些已经使用了错误类型的css的网站,但这也不代表这规则不能被打破。你可以假 设:黑客基本不太可能用合法的css去感染一个文档。我想说的是:我们可以确确实实的去一件事情——让一个页面使用字符集就可以合法的,正常的渲染。
css官方文档定义了一个css所需的字符集的优先级
如果一个页面没有明确的BOM或者content-type,那最后就会选择环境的编码值作为最后的编码选择,然而,环境编码是我们可控的。 其 中BOM这个可以不谈,因为很少用到。尽管出于各种原因,我们能看到很多网站并没指定content-type头的字符集,但是content-type 头来设置字符集其实有那么点点暴力,现代的框架都会对其设置默认值。举个例子,facebook就是一个不设置content-type字符集的网站,但 是它用meta charset来指定字符集。
我们来看最有意思的部分:强行合法化css。在这之前我们先得了解基本的语法。
一个css就是个样式表。它必须以“@ ”规则开头 或者是选择器开头。我们就只看下规则集
一个规则本质上就是又“选择器”+“代码块”组成的。选择器有很多种,但是大部分都是有一个标识符的。根据这篇说明,标识符只能包含a-zA-Z0-9和ISO 10646字符集U+00A0,又或者是更高,还有就是“-”和“_”。很明显,css标识符支持大范围的unicode字符集(U+00A0 ~ U+10FFFF),但是引号之类都会被视为非法字符。
不像别的字符集,UTF-16通常由2个字节以上组成一个字符,甚至是ascii。
我们来看这个案例:我能告诉浏览器这个页面应该用UTF-16去渲染,然后,突然的整个文档就编程了一个合法标识符!因为整个转变过程中ascii字符 被”吃掉”了,包括换行和引号。当我们添加一个通配符让以后的规则都可以匹配这个元素。搞定了选择器后,解析器继续往下走。
到这一步,我们需要去找一个可以注入我们代码的地方并且创建一个代码块来执行我们的payload。我们需要一个可以写任意字符串的属性,这样才能导入我们要窃取的数据。”font-family”是最佳的选择。
好,我们来看现在我们分析到哪一步了
1 | Identifier(junk), * { font-family: Identifier(secret data) |
---|
恩,就是这样。哦!等等。。。闭合的“}”在哪?事实上,我们可以忽略掉它,因为这样依然是合法的。根据这篇文档,当一个文件被加载到末尾(EOF)后,代码块将自动的闭合。为了达到目的,我还需要一个注入点来执行。
你会怀疑:X-Content-Type-Options 不是用来防止嗅探的么?不幸的是,webkit在引入一个css的时候并不执行这个策略。换句话说就是,即使在头部设置了X-Content-Type-Options: nosniff也不能阻止这种跨域攻击。
限制
总结一下,这种攻击只有在以下情况才能成功。
Content-Type 字符集
“PoC || GTFO” – whoever
下面的poc将会演示如何从别人的phpinfo文件中截取cookie。phpinfo是常见的信息泄露,它包含http请求中的参数和一些服务端信 息。一般来说它不会受到xss攻击,用这个攻击方式的话,我们可以绕过http only来获取cookie,当然前提就是没设置字符集没过滤null。
PoC (Chrome 43, Safari 8 or iOS 8): http://innerht.ml/csstheft/phpinfo.html
最后webkit 拒绝了设置错误的MIME type的跨域加载
以上请求将提示禁止跨域加载。
虽然现代大部分浏览器修复了这个问题,但是一些个别浏览器依然是存在这个问题的。
https://www.mbsd.jp/Whitepaper/xssi.pdf
https://tools.ietf.org/html/draft-west-first-party-cookies-01#section-1.1
https://www.w3.org/TR/epr/
https://code.google.com/p/chromium/issues/detail?id=419383
http://www.phpied.com/css-railroad-diagrams/