目录
任务2 上网搜索一份XSS的fuzz字典或字典生成工具(可选)
任务4 总结浏览器解析机制,解释《漏洞利用之XSS注入》中15条中,至少5条执行成功或不成功的原因。(可选)
也是一样,先简单看一下课上讲的内容再写作业。
XSS漏洞简介
跨站脚本攻击(Cross Site Scripting),为不和层叠样式:表(Cascading Style Sheets,CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS由于Web应用程序对用户输入的数据没有进行充分的验证和过滤。攻击者可以利用这一漏洞,将恶意脚本代码嵌入到用户输入的数据中,例如如表单提交、URL参数、Cookie等。当这些数据被Web应用程序接收并嵌入到网页中时,恶意脚本就会被执行。
XSS(Cross-sitescripting)注入是一种针对Web应用相程序的安全漏洞,攻击者利用该漏洞向Web页面中注入恶意代码,当其他用户访问该)页面时,这些恶意代码就会被执行,从而使攻击者能够窃取用户的信息、纂改用户的数据,甚至控制用户的账户等。
XSS分类
存储型XSS
存储型XSS又被称为持久性XSS,存储型XSS是最危险的一种跨站脚本漏洞,当攻击者提交一段XSS代码后,被服务端接收并存储,当攻击者或用户再次访问某个页面时,这段XSS代码被程序读出来响应给浏览器,造成XXS跨站攻击,这便是存储型XSS。
反射型XSS
反射型XSS也被称为非持久性XSS,当用户访问一个带有XSS代码的HTML请求时,服务器端接收数据后处理,然后把带有XSS的数据发送到法别览器,浏览器解析这段带有XSS代码的数据后,就造成XSS漏洞,这个过程就像一次反射,所以叫反射型XSS。
DOM 型 XSS
不经过后端,DOM-based XSS漏洞是基于文档对象模型Document Object Model,DOM)的一种漏洞,dom-xss是通过url传入参数去控制触发的。
注意:大体上只分为存储型XSS和反射型XSS,反射型XSS包括DOM型XSS
XSS攻击步骤
存储型XSS
攻击者将恶意代码提交到目标网站的数据库中。
用户打开目标网站时,数据库中的恶意代码将会被拼接在HTM中返回给浏览器,用户浏览器接收到响应后解析执行,其中恶意代码也会被执行。
恶意代码窃取用户数据并发送到攻击者的网站。
这种攻击方法常见于能够进行意见提交、用户私信等场景,在提交恶意代码的时候需要进行多次提交,通过注释掉影响恶意代码解析的代码,实现恶意代码的拼接。
<script>/*
*/alter(1);/*
*/</script>
反射型XSS
攻击者通过构造出特殊的URL,其中包含了恶意代码。用户打开带有恶意代码的URL时,网站服务端将恶意代码从URL中取出,拼接在HTML中返回给浏览器。用户浏览器接收到响应并解析执行,其后恶意代码也会被执行。恶意代码窃取用户数据并发送到攻击者的网站。
这种攻击方法常见于能够通过URL传递参数的网站,比如网站跳转。注意这种self型反射需要结合钓鱼来使用,漏洞平台并不认可。
DOM型XSS
攻击者构造出特殊的URL,其中包含了恶意代码。
用户打开带有恶意代码的URL。
用户浏览器接收到响应并解析执行,前端JavaScript取出lURL中的恶意代码并执行。
恶意代码窃取用户数据并发送到攻击者的网站
XSS注入常用注入手段
// 直接注入
<script>alert('1')</script>
// img标签隐藏
<img src="1" onerror=alert(1)>
<img src="1" onerror=javascript:alert(1)>
<img src="1" onmouseover="alert(1)">
// input标签隐藏
<input onfocus="alert(1);">
<input onblur=alert (1) autofocus>
<input autofocus>
xss 常用标签及绕过姿势总结:xss 常用标签及绕过姿势总结 - FreeBuf网络安全行业门户
这个总结个人感觉比较全,大家感兴趣可以参考。
任务1 总结反射型、存储型、DOM型XSS特点和区别
反射型XSS | 存储型XSS | DOM型XSS | |
产生层面(即解析位置) | 前端浏览器 | 后端服务器 | 前端浏览器、是特殊的反射型XSS |
漏洞特征 | 一次性的、前端执行、不会储存在后端数据库 | 持久性的、前端执行、储存在后端数据库 | 一次性的、前端执行、不会储存在后端数据库、程序执行不依赖于服务器端的数据 |
被攻击对象 | 一般是攻击者去寻找的,需要将特定的URL给被攻击对象 | 广撒网的方式或者指定的方式,只要有用户访问这个链接就会中招 | 和反射型XSS被攻击对象差不多,都是给攻击对象放送特定的URL |
存储时间 | 既有即用,没有持久性 | 存储在服务器上,只要服务器不挂机或者是被干掉,就一直会有 | 和反射型一样 |
常出现位置 | 通常出现在网站的搜索栏、用户登录口等地方 | 常出现在网站的留言版、评论、博客日志等交互处 | 网页内嵌框架、JavaScript生成的内容、JavaScript事件处理器等 |
任务2 上网搜索一份XSS的fuzz字典或字典生成工具(可选)
任务3 到XSS挑战靶场(xss-labs)打靶
靶场链接:https://xss.tesla-space.com/
这个靶场我之前打过,写过一点博客,请移步个人博客链接
XSS-labs通关实践 – The-Starry-Sky
暂未完善完,因为之前写的有点low,所以打算趁这个机会完善一下,目前仅供参考。
目前完善到第五关。——2024.8.29
任务4 总结浏览器解析机制,解释《漏洞利用之XSS注入》中15条中,至少5条执行成功或不成功的原因。(可选)
在解析一篇HTML文档时主要有三个处理过程:HTML解析,URL解析和JavaScript解析。每个解析器负责解码和解析HTML文档中它所对应的部分。所以下面先把老师发的文档看一遍。
以下四个折叠块都来自老师课件,只做了一点小小的修改。
......放到csdn就没折叠块了,csdn不支持这玩意,我没找到,下面四个html、url、js解析和解析流可不看,因为就是老师上课的那个pdf,可以直接目录跳转食用我的总结,会不断更新完善。
HTML解析
从XSS的⻆度来说,我们需要关注的是HTML⽂档是如何被词法解析的,因为我们并不想让⽤户提供的数据最终被解析为⼀段可执⾏脚本的script标签。详细解析需要学习HTML词法解析细则。HTML词法解析细则是⼀篇冗⻓的⽂档,这篇⽂章只会覆盖有关⽂档解码如何结束,以及新token何时被创建这两个有趣的部分。
⼀个HTML解析器作为⼀个状态机,它从输⼊流中获取字符并按照转换规则转换到另⼀种状态。在
解析过程中,任何时候它只要遇到⼀个'<'符号(后⾯没有跟'/'符号)就会进⼊“标签开始状态
(Tag open state)”。然后转变到“标签名状态(Tag name state)”,“前属性名状态(before
attribute name state)”......最后进⼊“数据状态(Data state)”并释放当前标签的token。当解析器
处于“数据状态(Data state)”时,它会继续解析,每当发现⼀个完整的标签,就会释放出⼀个
token。
这⾥有三种情况可以容纳字符实体,“数据状态中的字符引⽤”,“RCDATA状态中的字符引
⽤”和“属性值状态中的字符引⽤”。在这些状态中HTML字符实体将会从“&#...;”形式解码,对应的
解码字符会被放⼊数据缓冲区中。例如,在问题4中,“<”和“>”字符被编码为“<”和“>”。当解析器解析完“<div>”并处于“数据状态”时,这两个字符将会被解析。当解析器遇到“&”字符,它会知道这是“数据状态的字符引用”,因此会消耗⼀个字符引用(例如“<”)并释放出对应字符的token。在这个例⼦中,对应字符指的是“<”和“>”。
思考:这是不是意味着“<”和“>”的token将会被理解为标签的开始和结束,然后其中的脚本会被执行?答案是脚本并不会被执⾏。原因是解析器在解析这个字符引用后不会转换到“标签开始状态”。正因为如此,就不会建立新标签。因此,我们能够利用字符实体编码这个行为来转义用户输⼊的数据从而确保用户输⼊的数据只能被解析成“数据”。
字符实体(character entities)
字符实体是⼀个转义序列,它定义了⼀般⽆法在文本内容中输⼊的单个字符或符号。⼀个字符实体以⼀个&符号开始,后面跟着⼀个预定义的实体的名称,或是⼀个#符号以及字符的十进制数字。
HTML字符实体(HTML character entities)
在HTML中,某些字符是预留的。例如在HTML中不能使用“<”或“>”,这是因为浏览器可能误认为它们是标签的开始或结束。如果希望正确地显示预留字符,就需要在HTML中使⽤对应的字符实体。<>的HTML字符实体描述如下:
需要注意的是,某些字符没有实体名称,但可以有实体编号。
字符引用(character references)
字符引用包括“字符值引用”和“字符实体引用”。在上述HTML例⼦中,'<'对应的字符值引用
为'<',对应的字符实体引用为‘<’。字符实体引用也被叫做“实体引用”或“实体”。)
现在你大概会明白为什么我们要转义“<”、“>”、“'” (单引号)和“"” (双引号)字符了。
HTML中有五类元素
- 空元素(Void elements),如<area>,<br>,<base>等等
- 原始文本元素(Raw text elements),有<script>和<style>
- RCDATA元素(RCDATA elements),有<textarea>和<title>
- 外部元素(Foreign elements),例如MathML命名空间或者SVG命名空间的元素
- 基本元素(Normal elements),即除了以上4种元素以外的元素
这五类元素区别如下:
- 空元素,不能容纳任何内容(因为它们没有闭合标签,没有内容能够放在开始标签和闭合标签
中间)。
- 原始⽂本元素,可以容纳文本。
- RCDATA元素,可以容纳文本和字符引用。
- 外部元素,可以容纳文本、字符引用、CDATA段、其他元素和注释
- 基本元素,可以容纳文本、字符引用、其他元素和注释
如果我们回头看HTML解析器的规则,其中有⼀种可以容纳字符引用的情况是“RCDATA状态中的字符引用”。这意味着在<textarea>和<title>标签中的字符引用会被HTML解析器解码。这里要再提醒⼀次,在解析这些字符引用的过程中不会进入“标签开始状态”。这样就可以解释问题5了。另外,对RCDATA有个特殊的情况。在浏览器解析RCDATA元素的过程中,解析器会进入“RCDATA状态”。在这个状态中,如果遇到“<”字符,它会转换到“RCDATA小于号状态”。如果“<”字符后没有紧跟着“/”和对应的标签名,解析器会转换回“RCDATA状态”。这意味着在RCDATA元素标签的内容中(例如<textarea>或<title>的内容中),唯⼀能够被解析器认做是标签的就是“</textarea>”或者“</title>”。
因此,在“<textarea>”和“<title>”的内容中不会创建标签,就不会有脚本能够执行。这也就解释了为什么问题6中的脚本不会被执行。
URL解析
URL解析器也是一个状态机模型,从输入流中进来的字符可以引导URL解析器转换到不同的状态。解析器的解析细则其中有很多有关安全或XSS转义的内容。
首先,URL资源类型必须是ASCII字母(U+0041-U+005A || U+0061-U+007A),不然就会进入“无类型”状态。。例如,你不能对协议类型进行任何的编码操作,不然URL解析器会认为它无类型。这就是为什么问题1中的代码不能被执行。因为URL中被编码的“javascript”没有被解码,因此不会被URL解析器识别。该原则对协议后⾯的“:”(冒号)同样适用,即问题3也得到解答。
然而,你可能会想到:为什么问题2中的脚本被执行了呢?如果你记得我们在HTML解析部分讨论的内容的话,是否还记得有⼀个情况叫做“属性值中的字符引用”,在这个情况中字符引用会被解码。我们将稍后讨论解析顺序,但在这⾥,HTML解析器解析了⽂档,创建了标签token,并且对href属性里的字符实体进⾏了解码。然后,当HTML解析器⼯作完成后,URL解析器开始解析href属性值里的链接。在这时,“javascript”协议已经被解码,它能够被URL解析器正确识别。然后URL解析器继续解析链接剩下的部分。由于是“javascript”协议,JavaScript解析器开始⼯作并执行这段代码,这就是为什么问题2中的代码能够被执行。
其次,URL编码过程使用UTF-8编码类型来编码每一个字符。如果你尝试着将URL链接做了其他编码类型的编码,URL解析器就可能不会正确识别。
JavaScript 解析
JavaScript解析过程与HTML解析过程有点不一样。JavaScript语言是一门内容无关语言。对应着有一份内容无关的语法来描述它。我们可以利用内容无关语法来解释JavaScript是如何解析的。
这⾥有⼀些与安全相关的事情:字符是如何被解码的?对⼀些字符进行转义是否有效?
开始之前,让我们来回到HTML解析过程中的“原始文本”元素。我故意将HTML中的⼀部分留到这个章节是因为它与JavaScript解析有关。所有的“script”块都属于“原始文本”元素。“script”块有个有趣的属性:在块中的字符引用并不会被解析和解码。如果你去看“脚本数据状态”的状态转换规则,就会发现没有任何规则能转移到字符引用状态。这意味着什么?这意味着问题9中的脚本并不会执行。所以如果攻击者尝试着将输⼊数据编码成字符实体并将其放在script块中,它将不会被执行。
那像“\uXXXX”(例如\u0000,\u000A)这样的字符呢,JavaScript会解析这些字符来执行吗?简单的说:视情况而定。具体的说就是要看被编码的序列到底是哪部分。首先,像\uXXXX⼀样的字符被称作Unicode转义序列。从上下文来看,你可以将转义序列放在3个部分:字符串中,标识符名称中和控制字符中。
字符串中:当Unicode转义序列存在于字符串中时,它只会被解释为正规字符,而不是单引号,双引号或者换行符这些能够打破字符串上下文的字符。这项内容清楚地写在ECMAScript中。因此,Unicode转义序列将永远不会破环字符串上下文,因为它们只能被解释成字符串常量。
标识符名称中:当Unicode转义序列出现在标识符名称中时,它会被解码并解释为标识符名称的一部分,例如函数名,属性名等等。
控制字符:当用Unicode转义序列来表示一个控制字符时,例如单引号、双引号、圆括号等等,它们将不会被解释成控制字符,而仅仅被解码并解析为标识符名称或者字符串常量。
总的来说,Unicode转义序列只有在标识符名称里不被当作字符串,也只有在标识符名称里的编码字符能够被正常的解析。如果我们回看问题11,它并不会被执⾏。因为“(11)”不会被正确的解析,而“alert(11)”也不是⼀个有效的标识符名称。问题12不会被正确执行要么是因为'\u0031\u0032'不
会被解释为字符串常量(因为它们没有用引号闭合)要么是因为它们是ASCII型数字。问题13不会
执行的原因是'\u0027'仅仅会被解释成单引号⽂本,而此时字符串是未闭合的。问题14能够执行的
原因是'\u000a'会被解释成换行符文本,这并不会导致真正的换行从而引发JavaScript语法错误。
解析流
在讨论过HTML,URL和JavaScript解析之后,读者应该能够对“什么会被解码”、“在什么地方被解码”和“如何被解码”这几件事有了清楚的认识。现在,另一个重要的概念是所有这些是如何协同工作的?在网页中有很多地方需要多个解析器来协同工作。因此,对于解码和转义问题,我们将简要的讨论浏览器如何解析一篇文档。
当浏览器从网络堆栈中获得一段内容后,触发HTML解析器来对这篇文档进行词法解析。在这一步中字符引用被解码。在词法解析完成后,DOM树就被创建好了,JavaScript解析器会介入来对内联脚本进行解析。在这一步中Unicode转义序列和Hex转义序列被解码。同时,如果浏览器遇到需要URL的上下文,URL解析器也会介入来解码URL内容。在这一步中URL解码操作被完成。由于URL位置不同,URL解析器可能会在JavaScript解析器之前或之后进行解析。考虑如下两种情况
Example A: <a href="UserInput"></a>
Example B: <a href=# οnclick="window.open('UserInput')"></a>
在例A中,HTML解析器将首先开始工作,并对UserInput中的字符引用进行解码。然后URL解析器开始对href值进行URL解码。最后,如果URL资源类型是JavaScript,那么JavaScript解析器会进行Unicode转义序列和Hex转义序列的解码。再之后,解码的脚本会被执行。因此,这里涉及三轮解码,顺序是HTML,URL和JavaScript。
在例B中,HTML解析器首先工作。然而接下来,JavaScript解析器开始解析在onclick事件处理器中的值。这是因为在onclick事件处理器中是script的上下文。当这段JavaScript被解析并被执行的时候,它执行的是“window.open()”操作,其中的参数是URL的上下文。在此时,URL解析器开始对UserInput进行URL解码并把结果回传给JavaScript引擎。因此这里一共涉及三轮解码,顺序是HTML,JavaScript和URL。
有没有可能解码次数超过3轮呢?考虑一下这个例子
Example C: <a href="javascript:window.open('UserInput')">
例C与例A很像,但不同的是在UserInput前多了window.open()操作。因此,对UserInput多了一次额外的URL解码操作。总的来说,四轮解码操作被完成,顺序是HTML,URL,JavaScript和URL。
重点总结如下(随理解和做示例不定时增加)
- 当浏览器从网络堆栈中获得一段内容后,不管怎么样,是都会先进行一次html解析,然后再视情况而定后续是url解析还是JS解析。
- url解析器规定协议、用户名、密码(这三个好像统称资源类型?)都必须是ASCII字母,协议类型(包括:冒号)不能进行任何编码,不然URL解析器会认为它无类型,从而导致url解码失败。
- 在“<textarea>”和“<title>”的内容中不会创建标签,不会有脚本能够执行。
- html在将html实体编码解析为字符后,例如将
<>
字符引用解析为<>后,不会转换到“标签开始状态”和“标签结束状态”,正因为如此,就不会建立新标签。这也是为什么有的网站将攻击者的输入中的特殊字符转换为html实体编码后,代码就无法执行的原因。也就是( htmlspecialchars()函数?)
个人理解:也就是说当进行html解码时,除了直接的<xxx>和</xxx>也就是没有进行html实体编码的标签会被解析为标签外,被进行了html实体编码的<>
即<>
不会在html解码为<>后再次被识别为标签。
解释示例
1 不执行
<a href="%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29"></a>
- 首先进行html解析,链接中无html编码内容,所以不用管。
- 然后href中是url内容,所以第二步要交给url解析器解析,url解析规定协议、用户名、密码都必须是ASCII字母,所以尽管href内容url解码后是
javascript:alert(1)
,但是仍然会解码失败,所以执行不成功。——重点总结2
2 执行
<a href="javascript:%61%6
c%65%72%74%28%32%29">
- 首先进行html解析,解析后变为
<a href="javascript:%61%6c%65%72%74%28%32%29">
。——重点总结1 - href是url,所以下一步交给url解析器,url解析器可以识别到为js协议,所以进行url解码后变为
<a href="javascript:alert(2)">
- 由于是js协议,所以解码后交给js解析器解析,从而得到执行。
3 不执行
<a href="javascript%3aalert(3)"></a>
- 首先进行html解析,链接中无html编码内容,所以不用管。
- 然后href中是url,所以要交给url解析器进行解析,但是url识别不出协议类型,因为url规定协议类型包括:(冒号)都不能进行任何编码,否则就会导致解码失败。而这里href中javascript后面跟的:(冒号)被进行了编码,所以执行不成功。——重点总结2
4 不执行
<div><img src=x onerror=alert(4)></div>
- 从HTML解析机制看,在读取 <div> 之后进⼊数据状态,
<
会被HTML解码为<
,但不会进⼊标签开始状态,当然也就不会创建 img 元素,也就是不会创建img标签,因此语句是无法执行的。——重点总结4
5 不执行
<textarea><script>alert(5)</script></textarea>
- 因为<textarea>是是 RCDATA 元素(RCDATA elements),其实不用管它是什么元素,只要记住在“<textarea>”和“<title>”的内容中不会创建标签,不会有脚本能够执行。——重点总结3
- 所以在进行html解码后为
<textarea><script>alert(5)</script></textarea>
,所以会直接显示<textarea>标签内的内容<script>alert(5)</script>
。——重点总结1
6 不执行
<textarea><script>alert(6)</script></textarea>
- 因为<textarea>是是 RCDATA 元素(RCDATA elements),其实不用管它是什么元素,只要记住在“<textarea>”和“<title>”的内容中不会创建标签,不会有脚本能够执行。——重点总结3
7 执行
<button onclick="confirm('7');">Button</button>
- 首先进行html解码,解码后变为
<button onclick="confirm('7');">Button</button>
——重点总结1 - onlick里面的是js代码,所以第二步会直接交给js解析器,从而可以得到执行。
8 不执行
<button onclick="confirm('8\u0027);">Button</button>
- 首先进行html解析,链接中无html编码内容,所以不用管。
- onlick里面的值是js代码,所以交给js解析器解析,而
\u0027
是单引号,在js中单引号不能Unicode编码,所以js不能执行。——重点总结5
9 不执行
<script>alert(9);</script>
- <script>中的内容会直接交给js解析器解析,在<script>块中的字符引用并不会被解析和解码。所以js不认识中间那一串html字符实体,所以执行失败。——重点总结6
- 中间那一串html解析后为
alert(9);
老师pdf上面这个代码少了两个;,我这个是补全之后解析的结果。
10 执行
<script>\u0061\u006c\u0065\u0072\u0074(10);</script>
- <script>中的内容会直接交给js解析器解析,这里js是能识别Unicode转义序列的,是因为这里的Unicode转义是标识符(函数名),而js是允许在标识符中使用Unicode的转义序列的。这里解析后是
alert(10);
,所以可以执行。——重点总结5
11 不执行
<script>\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0031\u0029</script>
- <script>中的内容会直接交给js解析器解析,这里unicode解码后是
alert(11)
,这里的Unicode转义有标识符(函数名),js是允许在标识符中使用Unicode的转义序列的。但是还有(),js中是不允许对控制字符如单双引号、左右括号等进行Unicode编码的,所以js解析失败,从而不能执行。——重点总结5
12 不执行
<script>\u0061\u006c\u0065\u0072\u0074(\u0031\u0032)</script>
- <script>中的内容会直接交给js解析器解析,这里unicode解码后是
alert(12)
,这里的Unicode转义有标识符(函数名),js是允许在标识符中使用Unicode的转义序列的。这里与11不同的是左右括号没有进行Unicode编码,但是它的参数解析后是12,而12不能被解析字符串常量,这是因为它们没有使用引号进行闭合——重点总结5 - 如果将括号内的Unicode编码加上双引号则该语句可正常执行。
13 不执行
<script>alert('13\u0027)</script>
- <script>中的内容会直接交给js解析器解析,这里unicode解码后是
alert('13')
,js中是不允许对控制字符如单双引号、左右括号等进行Unicode编码的,所以js解析失败,从而不能执行。——重点总结5
14 执行
<script>alert('14\u000a')</script>
- <script>中的内容会直接交给js解析器解析,这里unicode解码后是
alert('14\n')
,那个\u000a
解码后是\n
换行符,在一个字符串里面将换行符unicode编码在js中是允许的,所以js可以正常解析,可以执行。————重点总结5
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解析,解析后变为
<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>
——重点总结1 - href是url,所以下一步交给url解析器,url解析器可以识别到为js协议,因为它没有对协议类型和冒号进行url编码,所以进行url解码后变为
<a href="javascript:\u0061\u006c\u0065\u0072\u0074(15)"></a>
——重点总结2 - 由于是js协议,所以解码后交给js解析器解析,Unicode解码后
<a href="javascript:alert(15)"></a>
,这里js可以解析成功,因为它的Unicode转义序列是标识符所以可以识别,从而可以得到执行。——重点总结5
参考
- XSS的分类和原理:XSS的分类和原理_存储型xss和反射型xss-CSDN博客
- 三种XSS的区别:反射型XSS、存储型XSS及DOM型XSS到底有什么区别?
- xss 常用标签及绕过姿势总结:xss 常用标签及绕过姿势总结 - FreeBuf网络安全行业门户