XSS
- 1. XSS的原理
- 2. Xss漏洞分类
- 2.1 反射性xss
- 2.2 存储型XSS
- 2.3 基于DOM的 XSS
- 2.4 XSS漏洞的危害
- 3. XSS的各种bypass技巧
- 4. 从 XSS Payload 学习浏览器解码
- 5. 浏览器解析机制
- 5.1 HTML中有五类元素:
- 5.2 五类元素的区别
1. XSS的原理
恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。XSS攻击针对的是用户层面的攻击!
2. Xss漏洞分类
2.1 反射性xss
反射型XSS 是非持久性、参数型的跨站脚本。反射型XSS 的JS 代码在Web应用的参数(变量)中,如搜索框的反射型XSS。在搜索框中,提交PoC[scriptalert(/xss/)/script],点击搜索,即可触发反射型XSS。注意到,我们提交的poc 会出现在search.php 页面的keywords 参数中。
2.2 存储型XSS
存储型XSS 是持久性跨站脚本。持久性体现在XSS 代码不是在某个参数(变量)中,而是写进数据库或文件等可以永久保存数据的介质中。存储型XSS 通常发生在留言板等地方。我们在留言板位置留言,将恶意代码写进数据库中。此时,我们只完成了第一步,将恶意代码写入数据库。因为XSS 使用的JS 代码,JS 代码的运行环境是浏览器,所以需要浏览器从服务器载入恶意的XSS 代码,才能真正触发XSS。此时,需要我们模拟网站后台管理员的身份,查看留言。
2.3 基于DOM的 XSS
DOM XSS 比较特殊。owasp 关于DOM 型号XSS 的定义是基于DOM 的XSS 是一种XSS 攻击,其中攻击的payload由于修改受害者浏览器页面的DOM 树而执行的。其特殊的地方就是payload 在浏览器本地修改DOM 树而执行, 并不会传到服务器上,这也就使得DOM XSS 比较难以检测。
2.4 XSS漏洞的危害
3. XSS的各种bypass技巧
Level 1
没有什么限制,直接弹窗
Level 2
从上图源码可知,在箭头1处将get方式传递到服务器端的keyword参数的值赋给str变量。在箭头2处是用htmlspecialchars()函数对变量str进行处理之后显示到网页上。但是在箭头3处却是直接将变量值插入到了input标签value属性值中,因为这里并没有对敏感字符进行编码和过滤,所以可以通过构造实现XSS攻击。
<input name=keyword value="" > scriptalert('xss')/script //"
Level 3
onfocus是javascript中在对象获得焦点时发生的事件,最简单的实例就是网页上的一个输入框,当使用鼠标点击该输入框时输入框被选中可以输入内容的时候就是该输入框获得焦点的时候,此时输入框就会触发onfocus事件.因此点击当前页面的输入框就可以完成弹框了。
http://localhost/level3.php?keyword=scriptalert('xss')/script&submit=搜索
Level 4
原来如此,在服务器端先是将传递过来的keyword参数的值赋给str变量,然后经过箭头1和箭头2处的处理将变量值中包含的<、>符号删除。最后在箭头3处对变量值进行编码处理之后显示在页面之上,在箭头4处将去除特殊符号后的变量值插入到input标签的value属性值中。
http://localhost/level4.php?keyword="οnfοcus=javascript:alert('xss') "
Level 5
从源码来看,服务器端先是将传递过来的参数值转换为全小写之后赋值给变量str,接着就是通过str_replace()函数来破坏变量值中的敏感字符的语义。最后在箭头4处通过htmlspecialchars()函数处理之后显示到网页上,在箭头5处直接将进行敏感字符处理之后的变量值插入到input标签的value属性值中。
http://localhost/level5.php?keyword="> <a href=javascript:alert('xss') > xss/a//
Level 6
从源码来看服务器端做的防护措施比我们想象的要多得多。接下来也会根据图中的一些代码来提一提在前五关中没有提过的执行js代码的其他一些方式。
从箭头1的地方可以看到是用字符<script去匹配我们提交的参数值,如果匹配到了就进行替换来破坏原来的语义导致无法实现XSS。此处能够防范的是script/script这一类的恶意代码。
从箭头2的地方可以看到是用字符on去匹配参数值,如果匹配到了就进行替换破坏原有语义。这里主要防范的是利用带有on字符的事件来触发恶意代码,比如前面用到过的onfocus事件。
从箭头3的地方可以看到是用字符src去进行匹配,但是貌似我们之前没有提到过含有此类字符的恶意代码啊。说到这里我们就不得不提到img标签了。熟悉html的人都会知道在img标签中引用图片会用到一个属性就是src。正常的引用图片就是将待引用图片的地址赋值给src属性。但是在js中如果src属性的值不正常或者无法访问到时就可以触发一个onerror事件来执行js代码。
http://localhost/level1.php?name=<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgieHNzIik8L3NjcmlwdD4=">ceshi/a
Level 7
可以看到因为在箭头1处首先是对参数值转换成了小写,所以上一关的大小写绕过才没能奏效。而在箭头2处又将基本的关键字都删除了。但是这里的字符替换操作仅仅执行了一次,因为比如在javascrscriptipt中在匹配的时候仅仅匹配到了一个script字符,所以也就只是将中间该字符删除而并不会接着再对结果字符串进行同样的操作了。
Level 8
箭头1处可以看到对参数值做了小写处理,在箭头2处对常见的关键字做了过滤处理,在箭头3处还将用来起闭合作用的引号做了字符实体替换。
<img src=1 onerror=" alert(1)">
Level 9
可以看到在箭头1处就是对参数值进行小写处理,然后就是对关键字的过滤,跟前面几关的做法是一样的。唯一不同之处就是在下面对处理过后的字符还做了一个查找,如果该字符中含有http://就返回第一次出现的位置,也就可以将该字符插入到href属性值中了,但是如果字符中没有http://的话就会返回false,接着在href属性值中就会出现链接不合法这样的字样。
<img src=1 onerror=" alert(1)">//https://
Level 10
服务器端在箭头1处说明是接收t_sort参数值的。然后在箭头2处会删除t_sort参数值中的<、>。从这里来看的话这一关就只能是将js代码插入到input标签的属性值中来执行而不能通过闭合input标签引入新的标签来触发XSS了。
http://localhost/level10.php keyword=scriptalert('xss')/script&t_sort="type="text" οnclick="alert('xss')
4. 从 XSS Payload 学习浏览器解码
1
<a href="%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29"></a>
里面没有HTML编码内容,不考虑,其中href内部是URL,于是直接丢给URL模块处理,但是协议无法识别(即被编码的javascript:
),解码失败,不会被执行
URL规定协议,用户名,密码都必须是ASCII,编码当然就无效了
2
<a href="javascript:%61%6c%65%72%74%28%32%29">
先HTML解码,得到
<a href="javascript:%61%6c%65%72%74%28%32%29">
href中为URL,URL模块可识别为javascript
协议,进行URL解码,得到
<a href="javascript:alert(2)">
由于是javascript协议,解码完给JS模块处理,于是被执行
3
<a href="javascript%3aalert(3)"></a>
同1,不解释
4
<div><img src=x onerror=alert(4)></div>
这里包含了HTML编码内容,反过来以开发者的角度思考,HTML编码就是为了显示这些特殊字符,而不干扰正常的DOM解析,所以这里面的内容不会变成一个img元素,也不会被执行
从HTML解析机制看,在读取<div>
之后进入数据状态,<
会被HTML解码,但不会进入标签开始状态,当然也就不会创建img
元素,也就不会执行
5
<textarea><script>alert(5)</script></textarea>
<textarea>
是RCDATA
元素(RCDATA elements),可以容纳文本和字符引用,注意不能容纳其他元素,HTML解码得到
<textarea><script>alert(5)</script></textarea>
于是直接显示
RCDATA`元素(RCDATA elements)包括`textarea`和`title
6
<textarea><script>alert(6)</script></textarea>
同5,不解释
7
<button onclick="confirm('7');">Button</button>
这里onclick
中为标签的属性值(类比2中的href
),会被HTML解码,得到
<button onclick="confirm('7');">Button</button>
然后被执行
8
<button onclick="confirm('8\u0027);">Button</button>
onclick
中的值会交给JS处理,在JS中只有字符串和标识符能用Unicode表示,'
显然不行,JS执行失败
9
<script>alert(9);</script>
script
属于原始文本元素(Raw text elements),只可以容纳文本,注意没有字符引用,于是直接由JS处理,JS也认不出来,执行失败
原始文本元素(Raw text elements)有<script>
和<style>
10
<script>\u0061\u006c\u0065\u0072\u0074(10);</script>
同8,函数名alert
属于标识符,直接被JS执行
11
<script>\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0031\u0029</script>
同8,不解释
12
<script>\u0061\u006c\u0065\u0072\u0074(\u0031\u0032)</script>
这里看似将没毛病,但是这里\u0031\u0032
在解码的时候会被解码为字符串12
,注意是字符串,不是数字,文字显然是需要引号的,JS执行失败
13
<script>alert('13\u0027)</script>
同8
14
<script>alert('14\u000a')</script>
\u000a
在JavaScript里是换行,就是\n
,直接执行
Java菜鸡才知道在Java里\u000a
是换行,相当于在源码里直接按一下回车键,后面的代码都换行了
15
<a href="javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(15)"></a>
先HTML解码,得到
<ahref="javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(15)"></a>
在href中由URL模块处理,解码得到
javascript:\u0061\u006c\u0065\u0072\u0074(15)
识别JS协议,然后由JS模块处理,解码得到
javascript:alert(15)
最后被执行
5. 浏览器解析机制
5.1 HTML中有五类元素:
1. 空元素(Void elements),如<area>,<br>,<base>等等
2. 原始文本元素(Raw text elements),有<script>和<style>
3. RCDATA元素(RCDATA elements),有<textarea>和<title>
4. 外部元素(Foreign elements),例如MathML命名空间或者SVG命名空间的元素
5. 基本元素(Normal elements),即除了以上4种元素以外的元素
5.2 五类元素的区别
1. 空元素,不能容纳任何内容(因为它们没有闭合标签,没有内容能够放在开始标签和闭合标签中间)。
2. 原始文本元素,可以容纳文本。
3. RCDATA元素,可以容纳文本和字符引用。
4. 外部元素,可以容纳文本、字符引用、CDATA段、其他元素和注释
5. 基本元素,可以容纳文本、字符引用、其他元素和注释
这里涉及三轮解码,顺序是HTML>URL>JavaScript