前言


每个月都得学点什么,以前对Dom Xss 只有一个模糊的印象,就是看不懂。在xss中,分为反射型,存储型和DOM型XSS,而且难以防范,在安全小课堂中,Camaro师傅就介绍过Dom Xss的优势:

  • 避开waf

    因为有些情况Dom Xss的Payload,可以通过location.hash,即设置为锚部分从#之后的部分,既能让JS读取到该参数,又不让该参数传入到服务器,从而避免waf检测。location.search也类似,它可以把部分参数放在?之后的部分。

  • 长度不限

    这个很重要,关键时候!长度不够,可不是什么小药丸就解决的。

  • 隐蔽性强

    攻击代码可以具有隐蔽性,持久性。例如使用Cookie和localStorage作为攻击点的DOM-XSS,非常难以察觉,且持续的时间长。

图片来自

常见场景


跳转

在很多场景下,业务需要实现页面跳转,常见的使用,location.href() location.replace() location.assign()这些方法通过Javascript实现跳转。我们第一时间可能想到的是限制不严导致任意URL跳转漏洞,而DOM XSS与此似乎“八竿子打不着”,实际上跳转部分参数可控,可能导致Dom xss。

首先我们来看个简单的例子:

var hash = location.hash;
if(hash){
    var url = hash.substring(1);
    location.href = url;
}

变量hash为可控部分,并带入url中,变量hash控制的是#之后的部分,那么可以使用伪协议#javascript:alert(1)

这里扩展下,常见的几种伪协议"javascript:","vbscript:","data:"

IE下"vbscript:"

#vbscript:msgbox(IE)

"data:"

#data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==

使用indexOf判断URL参数是否合法

var t = location.search.slice(1)       // 变量t取url中?之后的部分
if(t.indexOf("url=") > -1 && t.indexOf("http") > -1){  // 限定传入url中要带有indexOf的关键词
    var pos = t.indexOf("url=")+4;       // 往后截取
    url = t.slice(pos,t.length);         
    location.href = url                 // 跳转
}

indexOf会对url进行判断,是否存在关键字http,两个关键字都满足才能执行下面的部分,如果正常请求 ?url=http://cos.top15.cn 没问题,我们构造javascript:alert(1),并不会弹窗,正如我们上段所言,需要满足indexOf带有的关键字,所以只要构造javascript:alert(1)//http即可完成攻击,有的匹配indexOf("http://cos.top15.cn"),看似好像没问题,其实构造javascript:alert(1)//http://cos.top15.cn即可绕过,实际上这种使用indexOf来判断跳转来路域名的方法是不负责任,容易被绕过。

正则表达式缺陷

对跳转的url,通过正则进行判断是否合法http(s),容易忽略元字符^(匹配行的开始位置),加上和不加上,过滤的效果具有天壤之别。因为正则并没有严格限定跳转的url必须是http(s)开头,那么javascript:alert(1)//http://cos.top15.cn即可绕过。还有一些正则要求匹配上一些符号字符串参数类的加上就可以了,主要得看得懂令人头晕的正则

取值写入页面或动态执行

接受url在前端显示,例如名称,地点,标题等,一般标题等都会将<>html实体编码,但在上传文件处,文件的的标题之类的,可能不会太重视。

innerHTML

<div id="msgboard"></div>
<script>
 let hash = location.hash;
    if (hash.length > 1) {
        let hashValueToUse = unescape(hash.substr(1));
        let msg = "Welcome <b>" + hashValueToUse + "</b>!!";
        document.getElementById("msgboard").innerHTML = msg;
    }
</script>

innerHTML属性可以设置或者返回指定元素的HTML内容,此属性使用频繁且极为简单。如上代码变量hash是可控的,取值后,通过innerHTML写入div中。

以下三个属性都可以修改节点,innerHTML \ outerHTML 使用时要注意,是否写入标签,标签需要进行编码处理。而innerText就比较特殊,它自动将HTML标签解析为普通文本,所以HTML标签不会被执行,避免XSS攻击。

图片来自

document.write

document.write方法可以在文档中写入指定的字符串。

var hash = location.hash.slice(1);
document.write(hash);

上述例子很简单,location.hash的#之后是可控部分传递数据,document.write接收执行。

eval

执行一段由JavaScript代码组成的字符串。

eval("var x = '" + location.hash + "'");

和上面例子一样,有可控外部参数带入数据,接收并执行。慎用危险的eval,还有定时器方法是setIntervalsetTimeout

特殊取值

localStorageSessionStorageCookies储存源中取数据,这些值往往会被认为来源相对可信,未进行处理

let payloadValue = localStorage.getItem("payload", payload);
let msg = "Welcome " + payload + "!!";
document.getElementById("msgboard").innerHTML = msg;

https://domgo.at/cxss/example/6来演示

这里localStorage是数据来源,innerHTML是接受并执行。此外还有document.referrerwindow.namepostMessage都值得关注,也容易造成Dom xss,触发点不同,document.referrer可能需要从上一页 / 上面的url,才能触发。

最后


写完这篇水文后。。。如有错误,请师傅指正。

参考


点击收藏 | 1 关注 | 2
登录 后跟帖