今天在给客户做渗透测试时,遇到了一处XSS。虽然很简单,但有点小意思。引发了我对js转义和html转义在XSS中的思考,故做个小笔记记录一下。两个例子都会以仿写现实场景的代码的说明问题。
0x01 一点知识贮备
1.1 关于转义
**;
格式的字符串是html的转义字符,是JS的转义符,转义的目的就是告诉解析器该符号为字符,而不是代码,防止代码出现歧义。
1.2 浏览器解析原则
- 若果存在html转义字符串,HTML解析引擎会先把转义字符解析为字符串
- HTML解析引擎按照从上到下,从外向里解析html标签
- 遇到html标签浏览器会让html解析引擎解析,遇到
标签,浏览器会让JS解析引擎对标签内容进行解析。
1.3 html源码和浏览器解析结果
在浏览器中我们按住快捷键ctrl+u,看到的是服务器接受我们的请求后返回的html源码。按F12进入开发者工具面板,开发者工具分析出的DOM结构,就是浏览器的解析结果。
ps:html源代码DOM结构和浏览器解析后的DOM结构是有区别的!
0x02 XSS与JS转义
2.1 测试代码和问题描述
1 |
|
当我们提交,前端没有出现我们期待的弹窗,而是输出了以下字符串。
1 |
"; if(input_str.length>0){ document.write("Your input:"+input_str); } |
而当我们提交,则可以正常弹框。如何解释这两种情况,我们来思考一下?
2.2 原理分析
当我们输入第一个payload提交后,得到的html源码如下:
1 |
html> |
当我们的HTML解析器解析到标签时,它会快速去查找离它最近的闭合标签
。这时它查找到是8行中的
,而不是12行的
。这时
标签内的
var input_str = "
被交给js引擎去解析。而8行和12行的
之间的代码被当成字符串输出到前端页面。而由于6行
标签没有配对成功,故不会被浏览器解析为一个合法标签。 所以最终的解析结果是第8行的
被解析为字符串,
被解析为html标签。
当我们输入第二个payload提交后,得到的html源码如下,与上面代码类似,只是差异只在第8行(多了一个/)。
1 |
html> |
还是同样的解析原则,html解析引擎解析到7行的时,它会快速去查找离它最近的闭合标签
。这是在到第8行时发现
标签,而不是
,
故继续往下,直到找寻到12行的标签,才完成了配对。这时8行和11行的代码交给了js引起去解析。由于
双引号包围,所以js解析器会把它当字符串处理。 所以最终的解析结果是第8行中的
和
都是字符串而不是标签。
值得注意的是第8行当中的字符的引入使得标签在html解析引擎解析时未在第8行被闭合,同时又因为为js语法中的转义字符,故在js解析引擎解析时,又能正常解析input_str变量的值为
字符串,所以最总成功弹窗,很巧妙!
这些解析结果都是可以使用浏览器自带的F12开发者工具开验证。
0x03 XSS与html转义
3.1 测试代码与问题描述
1 |
|
我们将javascript:alert(1);
html转义得到如下字符串,并填写到str1输入框
1 |
javascript:alert(1); |
我们将html转义后得到如下字符,并填写到str2输入框
1 |
<script>alert(1);</script> |
提交后发现点击str1链接可以弹框,说明前者被当代码来执行了,而后者被当字符串输出了。我们来看这时为何?
3.2 原理分析
提交payload之后,服务器返回的html代码如下:
1 |
html> |
而浏览器html解析器解析后的结果如下:
1 |
html> |
通过解析结果,我们可以很容易看到。payload其实都被当成了字符输出了。只是在点击str1连接时,前者被解码之后的字符被当代码执行了。而后者被浏览器html解析器解码后为<script>alert(1);</script>
,而不是,所以js代码自然无法执行。所以str2应该为
,才可以触发XSS。
0x04 总结
通过对js转义和html转义在XSS中的应用,让我对浏览器解析html代码的解析过程有了更深的了解。可以借鉴其中的原理来构造更简洁,精巧的XSS的payload,也可以尝试用来绕waf。
参考文章
文章来源于gv7.me:XSS中的JS转义和HTML转义
客户:你上周发的渗透测试报告中说存在有148处XSS。今天开发需要修复,但你的渗透测试报告只列举了三处。开发需要提供所有存在漏洞的地址,才能修复完整。 我:其实可以在系统数据提交的入口,对get和post数据包中参数进行过滤就好了。那样就修改一处就可以了。 客…
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论