標題:XSS 漏洞相關

taibeihacker

Moderator

XSS 漏洞相关​

1 定义及原理​

XSS(跨站腳本攻擊),瀏覽器將用戶輸入的內容當做腳本執行,執行了惡意的功能,這種針對用戶瀏覽器的攻擊,即跨站腳本攻擊
主要分為三個類型:
反射型
存儲型
DOM 型
XSS 危害:
盜取cookie
盜取賬戶
惡意軟件下載
鍵盤記錄
廣告引流

2 反射型 XSS​

2.1 原理​

應用程序或API 包含未经验证和未经转义的用户输入,直接作为 HTML 输出的一部分。一個成功的攻擊可以讓攻擊者在受害者的瀏覽器中執行任意的HTML 和JavaScript。
特點:非持久化,必須用戶點擊帶有特定參數的鏈接才能引起。
影響範圍:僅執行腳本的用戶。

3 存储型 XSS​

3.1 原理​

存儲型XSS 是指應用程序通過Web 請求獲取不可信賴的數據,在未檢驗數據是否存在XSS 代碼的情況下,便將其存入数据库。當下一次從數據庫中獲取該數據時程序也未对其进行过滤,頁面再次執行XSS 代碼,存儲型XSS 可以持續攻擊用戶。
存儲型XSS 出現位置:
留言板
評論區
用戶頭像
個性簽名
部落格

4 DOM 型 XSS​

4.1 原理​

4.1.1 DOM​

DOM 模型用一個逻辑树來表示一個文檔,每個分支的終點都是一個節點(node),每個節點都包含著對象(objects)。 DOM 的方法(methods)讓你可以用特定方式操作這個樹,用這些方法你可以改變文檔的結構、樣式或者內容。
20210110100040.png-water_print

4.1.2 DOM XSS​

DOM 型XSS 其實是一種特殊類型的反射型XSS,通過JS 操作 DOM 树動態地输出数据到页面,而不依賴於將數據提交給服務器端,它是基於DOM 文檔對像模型的一種漏洞。
1
2
3
4
5
6
7
html
body
script
document.write('scriptalert(1)\/script')
/script
/body
/html

4.1.3 示例​

首先這是一個DOM XSS,產生的原因是JS 代碼動態拼接了一個類似這樣的代碼:
1
$('head').append('meta'+text+'/meta')
以下面的POC 為例:
20210110135714.png-water_print

可以看到div 中的代碼是被HTML 實體編碼後的形式,但是最後結果還是會彈窗
20210110135839.png-water_print

原因在於innerHTML 輸入進去的代碼是不會被執行的。
比如你按如下代碼來動態插入一個DOM節點
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
!DOCTYPE html
!DOCTYPE html
html lang='en'
head
meta charset='UTF-8'
meta http-equiv='X-UA-Compatible' content='IE=edge'
meta name='viewport' content='width=device-width, initial-scale=1.0'
titleDOM XSS POC/title
/head
body
div id='demo'lt;scriptgt;alert`1`lt;/scriptgt;/div
script src='https://libs.baidu.com/jquery/2.1.1/jquery.min.js'/script
br
div id='test'/div
script
document.getElementById('test').innerHTML=document.getElementById('demo').innerHTML + '';
/script
/body
/html
會發現div id=test 標籤不會被執行,但是jquery 之類的框架會在插入的時候把節點的標籤eval 下,使得它可以執行,因為這個append() 方法本身就是要讓插入的元素執行,有這個需求的。

4.1.4 与反射型 XSS 的异同与危害​

同:都是沒有控制好輸入,並且把javascript 腳本輸入作為輸出插入到HTML 頁面。
异:反射型XSS 是经过后端语言後,頁面引用後端輸出生效。
DOM XSS 是經過JS 對DOM 樹直接操作後插入到頁面。
危害性:前後端分離,不經過WAF 的檢測。

5 伪协议与编码绕过​

5.1 伪协议​

偽協議不同於因特網上所廣泛使用的如http://、https//、ftp://在URL 中使用,用於執行特定的功能
Data 偽協議:
data:text/html;base64, PHNjcmlwdD5hbGVydCgxKTs8L3NjcmlwdD4=
JavaScript 偽協議:
javascript:alert('1')
20210110102339.png-water_print

5.2 编码绕过​

5.2.1 UNICODE 编码​

ISO(國際標誰化組織)制定的包括了地球上所有文化所有字母和符號的編碼,使用两个字节表示一個字符
Unicode 只是一個符號集,它只規定了符號的二進制代碼,卻沒有規定這個二進制代碼應該如何存儲。具體存儲由:UTF-8,UTF-16 等實現
20210110102858.png-water_print

5.2.2 浏览器解码​

解析一篇HTML 文檔時主要有三個處理過程:
HTML 解析並創建DOM 樹,URL 解析和JavaScript 解析。每個解析器負責解碼和解析HTML 文檔中它所對應的部分,且順序也有所區別。

5.2.3 HTML 解析过程​

5.2.3.1 解析过程​

HTML 有 5 类元素:空元素(Void elements),有area、base、br、col、command、embed、hr、img、input、keygen、link、meta、param、source、track、wbr 等
原始文本元素(Raw text elements),有script 和style
RCDATA 元素(RCDATA elements),有textarea 和title
外部元素(Foreign elements),例如MathML 命名空間或者SVG 命名空間的元素
基本元素(Normal elements),即除了以上4 種元素以外的元素
五类元素的区别如下:空元素,不能容納任何內容(因為它們沒有閉合標籤,沒有內容能夠放在開始標籤和閉合標籤中間)。
原始文本元素,可以容納文本。
RCDATA 元素,可以容納文本和字符引用。
外部元素,可以容納文本、字符引用、CDATA 段、其他元素和註釋
基本元素,可以容納文本、字符引用、其他元素和註釋
HTML 解析器以狀態機的方式運行,它從文檔輸入流中消耗字符並根據其轉換規則轉換到不同的狀態。
20210110212335.png-water_print

以如下代碼作為示例:
1
2
3
4
5
html
body
This is Geekby's blog
/body
/html
初始狀態為「Data」State,當遇到字符,狀態變為「Tag open」state,讀取一個a-z 的字符將產生一個開始標籤符號,狀態相應變為「Tag name」state,一直保持這個狀態直到讀取到,每個字符都附加到這個符號名上,例子中創建的是一個html 符號。
當讀取到,當前的符號就完成了,此時,狀態回到「Data」state,body 標籤重複這一處理過程。此時,html 和body 標籤都識別出來了。現在,回到「Data」State,讀取「This is Geekby’s blog」中的每個字符生成一個字符符號。
這樣直到遇到/body 中的。現在,又回到了「Tag open」,讀取下一個字符/,進入到「Close tag open」,創建一個閉合標籤符號,並且狀態轉移到「Tag name」state,還是保持這一狀態,直到遇到。然後,產生一個新的標籤符號並回到「Data」State。後面的閉合標籤處理過程同上。
資訊
HTML 解析器處於数据状态(Data State)RCDATA 状态(RCDATA State)属性值状态(Attribute ValueState)时,字符實體會被解碼為對應的字符。
示例
1
div#60;img src=x onerror=alert(4)#62;/div
和被編碼為字符實體#60; 和#62;
當HTML 解析器解析完div 時,會進入數據狀態並發布標籤令牌。
接著解析到實體#60; 時因為處在數據狀態,就會對實體進行解碼為,
後面的#62; 同樣道理被解碼為。
問題
被解碼後,img 是否會被解析為HTML 標籤而導致JS 執行呢?
因為解析器在使用字符引用後不會轉換到標籤打開狀態(Tag Open State),不進入標籤打開狀態就不會被發佈為HTML 標籤。因此,不會創建新HTML 標籤,只會將其作為數據來處理。

5.2.3.2 几种特殊情况​

原始文本元素
在HTML中,屬於Raw text elements 的標籤有兩個:script、style。在Raw text elements 類型標籤下的所有內容塊都屬於該標籤。
Raw textelements 類型標籤下的所有字符實體編碼都不會被HTML 解碼。 HTML 解析器解析到script、style 標籤的內容塊(數據)部分時,狀態會進入Script Data State,該狀態並不在我們前面說的會解碼字符實體的三條狀態之中。
因此,script#97;#108;#101;#114;#116#40;#57;#41;#59/script 這樣字符實體並不會被解碼,也就不會執行JS。
RCDATA 情況
在HTML中,屬於RCDATA 的標籤有兩個:textarea、title。
RCDATA Elements 類型的標籤可以包含文本內容和字符實體。
解析器解析到textarea、title 標籤的數據部分時,狀態會進入RCDATA State。
前面我們提到,處於RCDATA State 狀態時,字符實體是會被解析器解碼的。
示例
1
textarea#60;script#62;alert(5)#60;/script#62;/textarea
解析器解析到它們時會進行解碼
但是裡面的JS 同樣還是不會被執行,原因還是因為解碼字符實體狀態機不會進入標籤打開狀態(Tag Open State),因此裡面的script 並不會被解析為HTML 標籤

5.2.4 JavaScript 解析​

形如\uXXXX 這樣的Unicode 字符轉義序列或Hex 編碼是否能被解碼需要看情況。
首先,JavaScript 中有三個地方可以出現Unicode 字符轉義序列:
字符串中
Unicode 轉義序列出現在字符串中時,它只會被解釋為普通字符,而不會破壞字符串的上下文。
例如,scriptalert('\u0031\u0030');/script
被編碼轉義的部分為10,是字符串,會被正常解碼,JS 代碼也會被執行。
標識符中
若Unicode 轉義序列存在於標識符中,即變量名(如函數名等…),它會被進行解碼。
例如,script\u0061\u006c\u0065\u0072\u0074(10);/script
被編碼轉義的部分為alert 字符,是函數名,屬於在標識符中的情況,因此會被正常解碼,JS 代碼也會被執行。
控製字符中
若Unicode 轉義序列存在於控製字符中,那麼它會被解碼但不會被解釋為控製字符,而會被解釋為標識符或字符串字符的一部分。
控製字符即‘、'、() 等。
例如,scriptalert\u0028'xss');/script,( 進行了Unicode 編碼,那麼解碼後它不再是作為控製字符,而是作為標識符的一部分alert( 。
因此函數的括號之類的控製字符進行Unicode 轉義後是不能被正常解釋的。
示例
1
script\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0031\u0029/script
被編碼部分為alert(11)。該例子中的JS 不會被執行,因為控製字符被編碼了。
1
script\u0061\u006c\u0065\u0072\u0074(\u0031\u0032)/script
被編碼部分為alert 及括號內為12。該例子中JS 不會被執行,原因在於括號內被編碼的部分不能被正常解釋,要么使用ASCII 數字,要么加'' 或’ ’ 使其變為字符串,作為字符串也只能作為普通字符。
1
scriptalert('13\u0027)/script
被編碼處為'。該例的JS 不會執行,因為控製字符被編碼了,解碼後的' 將變為字符串的一部分,而不再解釋為控製字符。因此該例中字符串是不完整的,因為沒有' 來結束字符串。
1
scriptalert('14\u000a')/script
該例的JS 會被執行,因為被編碼的部分處於字符串內,只會被解釋為普通字符,不會突破字符串上下文。

5.2.5 URL 解析​

URL 解析器也被建模為狀態機,文檔輸入流中的字符可以將其導向不同的狀態。
首先,要注意的是URL 的協議部分必須為ASCII 字符,即不能被任何編碼,否則URL 解析器的狀態機將進入No Scheme 狀態。
示例
1
a href='%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29'/a
URL 編碼部分的是javascript:alert(1)。 JS 不會被執行,因為作為Scheme 部分的javascript 這個字符串被編碼,導致URL 解析器狀態機進入No Scheme 狀態。
URL中的: 也不能被以任何方式編碼,否則URL 解析器的狀態機也將進入No Scheme 狀態。
示例
1
a href='javascript%3aalert(3)'/a
由於: 被URL編碼為%3a,導致URL 狀態機進入No Scheme 狀態, JS 代碼不能執行。
示例
1
a href='#x6a;#x61;#x76;#x61;#x73;#x63;#x72;#x69;#x70;#x74;%61%6c%65%72%74%28%32%29'
javascript 這個字符串被實體化編碼, 沒有被編碼,alert(2) 被URL 編碼。可以成功執行。
首先,在HTML 解析器中,HTML 狀態機處於屬性值狀態(Attribute Value State)時,字符實體時會被解碼的,此處在href 屬性中,所以被實體化編碼的javascript 字符串會被解碼。
其次,HTML 解析是在URL 解析之前的,所以在進行URL 解析之前,Scheme 部分的javascript 字符串已被解碼,而並不再是被實體編碼的狀態。

5.2.6 解析顺序​

首先瀏覽器接收到一個HTML 文檔時,會觸發HTML 解析器對HTML 文檔進行詞法解析,這一過程完成HTML 解碼並創建DOM 樹。
接下來JavaScript 解析器會介入對內聯腳本進行解析,這一過程完成JS 的解碼工作。
如果瀏覽器遇到需要URL 的上下文環境,這時URL 解析器也會介入完成URL 的解碼工作,URL 解析器的解碼順序會根據URL 所在位置不同,可能在JavaScript 解析器之前或之後解析。 HTML 解析總是第一步。
URL 解析和JavaScript 解析,它們的解析順序要根據情況而定。
示例
1
a href='UserInput'/a
該例子中,首先由HTML 解析器對UserInput 部分進行字符實體解碼;
接著URL 解析器對UserInput 進行URL decode;如果URL 的Scheme 部分為javascript 的話,JavaScript 解析器會再對UserInput 進行解碼。所以解析順序是:HTML 解析-URL 解析-JavaScript 解析。
示例
1
a href=# onclick='window.open('UserInput')'/a
該例子中,首先由HTML 解析器對UserInput 部分進行字符實體解碼;
接著由JavaScript 解析器會再對onclick 部分的JS 進行解析並執行JS;
執行JS 後window.open(‘UserInput’) 函數的參數會傳入URL,所以再由URL 解析器對UserInput 部分進行解碼。
因此解析順序為:HTML 解析
 
返回
上方