XSS(DOM)
"Cross-Site Scripting (XSS)" attacks are a type of injection problem, in which malicious scripts are injected into the otherwise benign and trusted web sites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application using input from a user in the output, without validating or encoding it.
跨站點腳本(XSS)攻擊是一種注入攻擊,惡意腳本會被注入到可信的網站中。當攻擊者使用 web 應用程序將惡意代碼(通常以瀏覽器端腳本的形式)發送給其他最終用戶時,就會發生 XSS 攻擊。允許這些攻擊成功的漏洞很多,並且在 web 應用程序的任何地方都有可能發生,這些漏洞會在使用用戶的輸入,沒有對其進行驗證或編碼。
An attacker can use XSS to send a malicious script to an unsuspecting user. The end user's browser has no way to know that the script should not be trusted, and will execute the JavaScript. Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens, or other sensitive information retained by your browser and used with that site. These scripts can even rewrite the content of the HTML page.
攻擊者可以使用 XSS 向不知情的用戶發送惡意腳本,用戶的瀏覽器並不知道腳本不應該被信任,並將執行 JavaScript。因為它認為腳本來自可信來源,所以惡意腳本可以訪問瀏覽器並作用於該站點的任何 cookie、會話令牌或其他敏感信息,甚至可以重寫 HTML 頁面的內容。
DOM Based XSS is a special case of reflected where the JavaScript is hidden in the URL and pulled out by JavaScript in the page while it is rendering rather than being embedded in the page when it is served. This can make it stealthier than other attacks and WAFs or other protections which are reading the page body do not see any malicious content.
基於 DOM 的 XSS 是一種特殊的反射型 XSS,通過將 JavaScript 隱藏在 URL 中。基於 DOM 的 XSS 將在頁面呈現時被 JavaScript 拉出,而不是在服務時嵌入到頁面中。這會使它比其他攻擊更隱蔽,WAF 或其他保護讀取頁面正文時看不到任何惡意內容。
Run your own JavaScript in another user's browser, use this to steal the cookie of a logged in user.
在另一個用戶的瀏覽器中運行你自己的 JavaScript,用它竊取登錄用戶的 cookie。
Low Level
Low level will not check the requested input, before including it to be used in the output text.
在將請求的輸入包含在輸出文本中之前,Low level 將不檢查請求的輸入。

源碼審計
源碼如下,服務器沒有任何防御措施。
<?php
# No protections, anything goes
?>
接下來我們看一下前端的代碼,該頁面是個下拉頁面,用於選擇默認語言。F12 打開,點一點 HTML 標簽看到如下 JS 代碼。document 表示的是一個文檔對象,Location 對象包含有關當前 URL 的信息,href 屬性是一個可讀可寫的字符串,可設置或返回當前顯示的文檔的完整 URL。也就是說 “document.location.href” 的寫法得到頁面的 URL,而 indexOf() 方法可返回某個指定的字符串值在字符串中首次出現的位置,這里用來判斷 “default=” 是否在 URL 中。substring(start,stop) 方法用於提取字符串中兩個指定下標之間的字符,然后存到 lang 變量中,decodeURI() 函數可對 encodeURI() 函數編碼過的 URI 進行解碼。document.write 是 JavaScript 中對 document.open 所開啟的文檔流操作的 API 方法,它能夠直接在文檔流中寫入字符串。
if (document.location.href.indexOf("default=") >= 0) {
var lang = document.location.href.substring(document.location.href.indexOf("default=") + 8);
document.write("<option value='" + lang + "'>" + decodeURI(lang) + "</option>");
document.write("<option value='' disabled='disabled'>----</option>");
}
document.write("<option value='English'>English</option>");
document.write("<option value='French'>French</option>");
document.write("<option value='Spanish'>Spanish</option>");
document.write("<option value='German'>German</option>");
選擇下拉列表內容,選擇的值會賦給 default 並添加到 url 的末尾,再將其傳給 option 標簽的 value 結點。也就是說我們可以注入一些 JS 代碼進去,然后這部分會被包含到 lang 變量中,最終回顯到頁面上。
攻擊方式
HTML DOM 有個 alert() 方法,用於顯示帶有一條指定消息和一個 OK 按鈕的警告框。document.cookie 里面可以讀到 cookie 信息,我們可以把 cookie 放在一個 alert() 生成的警告框中,回顯時就會得到我們想要的信息了。注入的payload 如下所示:
<script>alert(document.cookie)</script>

注入 payload 之后,前端的代碼中會加入下面這個結點。

Medium Level
The developer has tried to add a simple pattern matching to remove any references to "<script" to disable any JavaScript. Find a way to run JavaScript without using the script tags.
開發人員嘗試添加一個簡單的模式匹配刪除對 “<script” 的任何引用,以此禁用任何 JavaScript,攻擊者需要找到一種不使用腳本標記運行 JavaScript 的方法。
源碼審計
前端代碼不變,后端代碼如下所示。array_key_exists() 函數檢查某個數組中是否存在指定的鍵名,如果鍵名存在返回 true,鍵名不存在則返回 false。stripos(string,find,start) 函數查找字符串在另一字符串中第一次出現的位置(不區分大小寫),header() 函數向客戶端發送原始的 HTTP 報頭。也就是說現在服務器通過一個模式匹配,過濾了 “script” 標簽,我們就不能直接注入 JS 代碼了。
<?php
// Is there any input?
if (array_key_exists("default", $_GET) && !is_null ($_GET[ 'default'])){
$default = $_GET['default'];
# Do not allow script tags
if (stripos ($default, "<script") !== false){
header ("location: ?default=English");
exit;
}
}
?>
攻擊方式
這種防御形同虛設,因為我們可以直接注入標簽將 cookie 顯示出來。HTML 的 < img > 標簽定義 HTML 頁面中的圖像,該標簽支持 onerror 事件,在裝載文檔或圖像的過程中如果發生了錯誤就會觸發。使用這些內容構造出 payload 如下,因為我們沒有圖片可供載入,因此會出錯從而觸發 onerror 事件輸出 cookie。
English</option></select><img src = 1 onerror = alert(document.cookie)>
注入 payload 之后,前端的代碼中會加入下面這個結點。

High Level
The developer is now white listing only the allowed languages, you must find a way to run your code without it going to the server.
開發人員現在設置了白名單,只允許傳遞語言單詞作為參數.你必須找到一種方法來運行你的代碼,不要讓它傳到服務器上。
源碼審計
前端代碼不變,后端代碼如下所示。服務器設置了白名單,default 參數只接受 French,English,German 以及 Spanish 這幾個單詞。
<?php
// Is there any input?
if (array_key_exists("default", $_GET) && !is_null ($_GET['default'])){
# White list the allowable languages
switch ($_GET['default']){
case "French":
case "English":
case "German":
case "Spanish":
# ok
break;
default:
header ("location: ?default=English");
exit;
}
}
?>
攻擊方式
可以在注入的 payload 中加入注釋符 “#”,注釋后邊的內容不會發送到服務端,但是會被前端代碼所執行。
English #<script>alert(document.cookie)</script>

Impossible Level
The contents taken from the URL are encoded by default by most browsers which prevents any injected JavaScript from being executed.
大多數情況下瀏覽器都會對 URL 中的內容進行編碼,這會阻止任何注入的 JavaScript 被執行。
<?php
# Don't need to do anything, protction handled on the client side
?>
服務器不需要多做什么,在客戶端會對 URL 進行編碼。
if (document.location.href.indexOf("default=") >= 0) {
var lang = document.location.href.substring(document.location.href.indexOf("default=") + 8);
document.write("<option value='" + lang + "'>" + (lang) + "</option>");
document.write("<option value='' disabled='disabled'>----</option>");
}
document.write("<option value='English'>English</option>");
document.write("<option value='French'>French</option>");
document.write("<option value='Spanish'>Spanish</option>");
document.write("<option value='German'>German</option>");
總結與防御
DOM 型 XSS 是特殊的反射性 XSS,是基於 DOM 文檔對象模型的漏洞。DOM (Document Object Model) 譯為文檔對象模型,是 HTML 和 XML 文檔的編程接口,可以使程序和腳本能動態訪問和更新文檔的內容、結構和樣式。HTML 標簽作為結點構成了 DOM 節點樹,樹中的節點都可以通過 JavaScript 進行訪問。

當網頁被瀏覽器請求是,瀏覽器會為頁面創建一個頂級的 Document object 文檔對象,然后生成各個子文檔的對象,每個頁面都會對應一個文檔對象,每個文檔對象都包含屬性、方法和事件。Document object 文檔對象可以通過 JavaScript 腳本進行編輯,客戶端可以通過 DOM 修改頁面的內容,從而獲取 DOM 中的數據在本地執行。由於這個漏洞存在於前端,因此 DOM 型 XSS 漏洞不需要和服務器交互。
XSS 的攻擊方式為攻擊者請求一個帶有 payload 的 URL,服務器的響應不會以任何形式包含攻擊者的腳本。當時當用戶的瀏覽器處理這個響應時,DOM 對象就會處理 XSS 代碼。XSS 漏洞的修復方式有以下 2 種:
- 過濾輸入的字符,例如 “ ' ”,“ " ”,“<”,“>” 等非法字符;
- 對輸出到頁面的數據進行編碼。
參考資料
dvwa-XSS(DOM)超詳細
DVWA系列(三)DOM型XSS
HTML DOM 教程
HTML < img > 標簽
