xss常见编码解析

前言

其实看这篇文章就差不多懂了:
https://www.cnblogs.com/b1gstar/p/5996549.html
这里只是记录一下方便理解

//1.URL 编码 "javascript:alert(1)"
<a href="%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29">123</a>

//2.HTML字符实体编码 "javascript" 和 URL 编码 "alert(2)"
<a href="&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;:%61%6c%65%72%74%28%32%29">123</a>

//3.URL 编码 ":"
<a href="javascript%3aalert(3)">123</a>

//4.HTML字符实体编码 < 和 >
<div>&#60;img src=x onerror=alert(4)&#62;</div>

//5.HTML字符实体编码 < 和 >
<textarea>&#60;script&#62;alert(5)&#60;/script&#62;</textarea>

//6.textarea中直接alert
<textarea><script>alert(6)</script></textarea>

//7.HTML字符实体编码 " ' " (单引号)
<button onclick="confirm('7&#39;);">Button</button>

//8.Unicode编码 " ' " (单引号)
<button onclick="confirm('8\u0027);">Button</button>

//9.HTML字符实体编码 alert(9);
<script>&#97;&#108;&#101;&#114;&#116&#40;&#57;&#41;&#59</script>

//10.Unicode 编码 alert
<script>\u0061\u006c\u0065\u0072\u0074(10);</script>

//11.Unicode 编码 alert(11)
<script>\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0031\u0029</script>

//12.Unicode 编码 alert 和 12
<script>\u0061\u006c\u0065\u0072\u0074(\u0031\u0032)</script>

//13.Unicode 编码 " ' " (单引号)
<script>alert('13\u0027)</script>

//14.Unicode 编码换行符(0x0A)
<script>alert('14\u000a')</script>

以上是一些xss编码解析的例子

首先需要知道html在解析相应的文档时可能会使用:html解析url解析javascript解析

html解析:

一个HTML解析器作为一个状态机,它从输入流中获取字符并按照转换规则转换到另一种状>态。在解析过程中,任何时候它只要遇到一个'<'符号(后面没有跟'/'符号)就会进入“标签开始状态(Tag open state)”。然后转变到“标签名状态(Tag name state)”,“前属性名状态(before attribute name state)”......最后进入“数据状态(Data state)”并释放当前标签的token。>当解析器处于“数据状态(Data state)”时,它会继续解析,每当发现一个完整的标签,就会释放出一个token。

例如:

<a href="127.0.0.1">123</a>

首先html匹配到<,进入标签开始状态,然后进入标签名状态,并匹配到a,然后进入前属性名状态,进行一系列属性名、属性值匹配,匹配完href="127.0.0.1"后,进入数据状态,匹配完数据123,结束标签,结束匹配

这大概就是html解析的简略过程,然后呢下面说一下几个概念

字符实体、引用

其实也就是html字符实体编码,例如:&#60;,&#62(<,>),html中也有一些预留的字符实体,称之为html字符实体,如:&lt;这两个都是为了转义用户输入的<或>而用的编码形式,使其不会成为一个新标签的开始或结束,也就是

解析器在解析这个字符引用后不会转换到"标签开始状态",只会将其当作"数据"处理

这也是为什么例4不会弹窗的原因

字符引用包括"字符值引用"和"字符实体引用",在上述例子中,'<'对应的字符值引用为\&#60;,对应的字符实体引用为\&lt;。字符实体引用也被叫做“实体引用”或“实体”。

下面有三种情况可以容纳字符实体:
"数据状态中的字符引用"
"RCDATA状态中的字符引用"
"属性值状态中的字符引用"

"数据状态中的字符引用"

第一种也就是在数据内容中可以用字符实体,如:

<a href="127.0.0.1">&#60;</a>

其中&#60;会被解析成<
在这里插入图片描述

"RCDATA状态中的字符引用"

要了解这个,首先需要知道在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种元素以外的元素

五类元素的区别如下:

  1. 空元素,不能容纳任何内容(因为它们没有闭合标签,没有内容能够放在开始标签和闭合标签中间)
  2. 原始文本元素,可以容纳文本
  3. RCDATA元素,可以容纳文本和字符引用
  4. 外部元素,可以容纳文本、字符引用、CDATA段、其他元素和注释
  5. 基本元素,可以容纳文本、字符引用、其他元素和注释

可以看到所谓RCDATA也就是一种html元素,而这种元素的标签为<textarea>或<title>
这意味着在<textarea>和<title>标签中的字符引用会被HTML解析器解码

在浏览器解析RCDATA元素的过程中,解析器会进入“RCDATA状态”。在这个状态中,如果遇到“<”字符,它会转换到“RCDATA小于号状态”。如果“<”字符后没有紧跟着“/”和对应的标签名,解析器会转换回“RCDATA状态”。这意味着在RCDATA元素标签的内容中(例如<textarea>或<title>的内容中),唯一能够被解析器认做是标签的就是它本身,即</textarea>或者</title>。因此,在<textarea>和<title>的内容中不会创建标签,就不会有脚本能够执行。所以例5,例6都不能执行,但他还是能解析实体编码:

<textarea>&#60;script&#62;alert(5)&#60;/script&#62;</textarea>

在这里插入图片描述
至于外部元素中的,CDATA:

我们来迅速看一下CDATA元素。任何在CDATA元素中的内容将不会触发解析器创建开始标签。闭合CDATA元素的标志是“]]>”序列。因此如果用户想逃出CDATA元素,就要用未经任何编码的“]]>”序列,不然是不会逃出CDATA元素的。

"属性值状态中的字符引用"

这部分将放到url解析中讲述

url解析

这个都比较清楚,着重看一下例1:

//1.URL 编码 "javascript:alert(1)"
<a href="%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29">123</a>

这里是:不能对协议类型进行任何的编码操作,不然URL解析器会认为它无类型

例1中对js伪协议(:也是其中一部分)进行了编码,导致url解析其为无类型,于是没有弹窗

再来看一下例2:

//2.HTML字符实体编码 "javascript" 和 URL 编码 "alert(2)"
<a href="&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;:%61%6c%65%72%74%28%32%29">123</a>

这里就用到了上面没说的:属性值状态中的字符引用
由于属性值状态中的字符实体是能被解析的,所以上面的代码首先经过html解析会变成:

<a href="javascript:%61%6c%65%72%74%28%32%29">123</a>

然后进行url解析,变成

<a href="javascript:alert(2)">123</a>

由此即可正常弹窗

例7也是一样:

//7.HTML字符实体编码 " ' " (单引号)
<button onclick="confirm('7&#39;);">Button</button>

这里&#39;作为属性值中的字符实体,先被解析成',然后与前面的单引号闭合弹窗

javascript解析

HTML五类元素中的第二类:原始文本元素中的<script>

就与js解析有关,而script块有个有趣的属性:在块中的字符引用并不会被解析和解码
看到例9

//9.HTML字符实体编码 alert(9);
<script>&#97;&#108;&#101;&#114;&#116&#40;&#57;&#41;&#59</script>

由于在script块中的字符实体编码不会被解析,所以不会弹窗

不过,js还支持unicode解析。根据文章,js是否会解析unicode编码并执行需要:"视情况而定"
具体要看被编码的序列到底是哪部分,unicode可以放在3个部分:字符串中,标识符名称中和控制字符中

字符串中

当Unicode存在于字符串中时,它只会被解释为正规字符,而不是单引号,双引号或者换行符这些能够打破字符串上下文的字符。因此,Unicode转义序列将永远不会破环字符串上下文,因为它们只能被解释成字符串常量。

标识符名称中

当Unicode转义序列出现在标识符名称中时,它会被解码并解释为标识符名称的一部分,例如函数名,属性名等等。
看例10:

//10.Unicode 编码 alert
<script>\u0061\u006c\u0065\u0072\u0074(10);</script>

这里unicode出现在alert这个函数中,允许被解析并执行

控制字符中

当用Unicode转义序列来表示一个控制字符时,例如单引号、双引号、圆括号等等,它们将不会被解释成控制字符,而仅仅被解码并解析为标识符名称或者字符串常量。如果你去看ECMAScript的语法,就会发现没有一处会用Unicode转义序列来当作控制字符。例如,如果解析器正在解析一个函数调用语句,圆括号部分必须为“(”和“)”,而不能是\u0028和\u0029。

说的已经比较详细了,还是看个例子:
例11

//11.Unicode 编码 alert(11)
<script>\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0031\u0029</script>

这里本来是alert(11),但是unicode并不能用来表示一个控制字符,如其中的(),所以不会弹窗

例13也是同样的不能用来表示单引号

//13.Unicode 编码 " ' " (单引号)
<script>alert('13\u0027)</script>

而例8中有onclick这个属性,所以也会调用js解析,不过也不会用来表示单引号

//8.Unicode编码 " ' " (单引号)
<button onclick="confirm('8\u0027);">Button</button>

例12看上去没有违背这个规则为什么没有弹窗

//12.Unicode 编码 alert 和 12
<script>\u0061\u006c\u0065\u0072\u0074(\u0031\u0032)</script>

因为unicode解码之后是ASCII型的数字,需要使用单引号闭合

<script>\u0061\u006c\u0065\u0072\u0074('\u0031\u0032')</script>

在这里插入图片描述

以上就是html、url、js解析器的简略内容

最后完善一下上面的例子:

//1.URL 编码 "javascript:alert(1)"
<a href="%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29">123</a>
//不会弹窗,js伪协议被url编码会被url解析器当作无类型

//2.HTML字符实体编码 "javascript" 和 URL 编码 "alert(2)"
<a href="&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;:%61%6c%65%72%74%28%32%29">123</a>
//会弹窗,经过html解析实体编码后得到javascript:,得到一个js伪协议

//3.URL 编码 ":"
<a href="javascript%3aalert(3)">123</a>
//不会弹窗,同1

//4.HTML字符实体编码 < 和 >
<div>&#60;img src=x onerror=alert(4)&#62;</div>
//不会弹窗,html实体不能当作新标签开始

//5.HTML字符实体编码 < 和 >
<textarea>&#60;script&#62;alert(5)&#60;/script&#62;</textarea>
//不会弹窗,由于是RCDATA 状态中的字符引用

//6.textarea中直接alert
<textarea><script>alert(6)</script></textarea>
//不会弹窗,同6

//7.HTML字符实体编码 " ' " (单引号)
<button onclick="confirm('7&#39;);">Button</button>
//会弹窗,属于属性值状态的字符引用

//8.Unicode编码 " ' " (单引号)
<button onclick="confirm('8\u0027);">Button</button>
//不会弹窗,属于控制符中的unicode,不能表示控制字符

//9.HTML字符实体编码 alert(9);
<script>&#97;&#108;&#101;&#114;&#116&#40;&#57;&#41;&#59</script>
//不会弹窗,script块中的字符实体编码不会被解析

//10.Unicode 编码 alert
<script>\u0061\u006c\u0065\u0072\u0074(10);</script>
//会弹窗,属于标识符名称中的unicode,用来表示alert

//11.Unicode 编码 alert(11)
<script>\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0031\u0029</script>
//不会弹窗,同8

//12.Unicode 编码 alert 和 12
<script>\u0061\u006c\u0065\u0072\u0074(\u0031\u0032)</script>
//不会弹窗,unicode解码后为ASCII类型,需要加引号

//13.Unicode 编码 " ' " (单引号)
<script>alert('13\u0027)</script>
//不会弹窗,同8

//14.Unicode 编码换行符(0x0A)
<script>alert('14\u000a')</script>
//会弹窗,因为用引号闭合
posted @ 2020-04-27 00:06  W4nder  阅读(2128)  评论(0编辑  收藏  举报