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>
//會彈窗,因為用引號閉合


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM