這一系列的博客文章將向你展示如何在單頁或富JavaScript的應用程式上識別DOM XSS的問題。作為示例,我們將在DOM XSS playground(https://domgo.at)上解決10個練習題目,並為檢測到的問題創建了簡單的概念證明漏洞。
這篇文章的內容涵蓋了前兩個練習的設置說明和解決方案。剩餘的練習將在我們發布的其他文章中提到。我們還將發布一個gitbook,其中包含了Appsecco書籍門戶網站上所有練習的解決方案。
更新:gitbook會掛在我們的圖書門戶網站上—— https://appsecco.com/books/automating-discovery-and-exploiting-dom-client-xss/
什麼是DOM XSS / Client XSS?
縱觀Cross Site Scripting漏洞的歷史,在測試人員和開發人員的心中都佔有特殊的地位。使用標準檢的測技術很難檢測到這種XSS的變體,並且相對的來說,這種漏洞的變體很容易出現在大型的JS應用程式中。
OWASP將其定義為XSS的漏洞類型,其中的原因是由於這種漏洞是在受害者瀏覽器中通過原始客戶端腳本修改DOM環境而執行攻擊有效載荷,因此客戶端代碼以一種 「意外」 的方式運行。也就是說,頁面本身(即HTTP響應)不會改變,但由於DOM環境中發生了惡意的修改,頁面中包含的客戶端代碼執行方式發生了改變。
簡而言之,當來自DOM源(如location.hash)的用戶輸入發現它賦值到了DOM接收器(如HTMLElement.innerHTML)時,就會發生客戶端XSS漏洞。DOM中有多個源,也可以有多個接收器,具體取決於JS的複雜程度和其所實現的功能。
通過手動的方式或代碼審查來檢測DOM XSS可能會花費大量的時間。一種可行的技術是通過一個工具從伺服器發送流量,該工具可以注入自己的JS來監控DOM變化,只需瀏覽網站即可枚舉所有源和接收器。
進入Sboxr
Sboxr是一個測試和調試Web應用程式的工具,尤其是大型的JavaScript應用程式。Sboxr通過在瀏覽器和伺服器之間的流量中注入它自己的JS代碼(稱為DOM傳感器)來工作,該代碼在使用站點時監視JS的使用情況,源,接收器,變量分配,函數調用等。然後,它通過其Web控制臺顯示用戶控制的數據在數據最終出現在執行接收器中時所採用的各種流的視圖。
設置Sboxr和Chrome
我們使用Ubuntu 18.04來設置我們的攻擊工具鏈以及Chrome 72。以下步驟將幫助你進行設置:
1、從供應商網站獲取Sboxr的許可副本 - https://sboxr.com/
2、運行Sboxr需要.NET 核心 SDK,可以按照這裡的(https://dotnet.microsoft.com/download/linux-package-manager/ubuntu18-04/sdk-current)說明在Linux上進行安裝。對於Windows系統,請按照這個(https://dotnet.microsoft.com/download)說明進行操作即可。
3、安裝完成後,通過運行dotnet Sboxr.dll啟動Sboxr
4、程序啟動後會在埠3333 http://localhost:3333/console 上訪問到Sboxr Web界面(用於管理和分析發現的問題),埠3331是一個代理埠。
5、如果你希望連結Burp或其他攔截代理,請瀏覽並單擊HTTP Sensor以設置上遊代理(例如Burp或OWASP ZAP)的IP位址和埠。
設置完成後,我們需要配置瀏覽器向Sboxr發送流量(然後可以轉發到Burp或OWASP ZAP)。
Sboxr目前還不支持SOCKS代理,因此你需要使用Burp或OWASP ZAP進行連結以阻止流量。
ED_:D_=>HTTPS站點可能無法與Sboxr一起正常工作,因為我們沒有應該要導入的證書。因此,我們使用--ignore-certificate-errors參數啟動Chrome(我們注意到Firefox的about:config中的禁用HSTS檢查的network.stricttransportsecurity.preloadlist選項有一些問題,因此我們暫時會一直使用Chrome)。
在Linux上,使用以下命令啟動Chrome:
mkdir -p ~/.chrome;/opt/google/chrome/chrome -incognito --ignore-certificate-errors --proxy-server=http=http://localhost:3331\;https=http://localhost:3331 --user-data-dir=~/.chrome
在Windows系統上,可以執行以下操作(假設你的安裝路徑也是標準的安裝路徑)
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" -incognito --ignore-certificate-errors --proxy-server=http=http://localhost:3331;https=http://localhost:3331 --user-data-dir="C:\Users\%Username%\AppData\Local\Temp\TestChromeProxy"\Program Files(x86)\Google \Chrome \Application \chrome.exe」-incognito --ignore-certificate-errors --proxy-server = http = http:// localhost:3331; https = http://localhost:3331 --user-data-dir =「C:\Users \%Username%\AppData \Local \Temp \TestChromeProxy」
檢測並利用DOM XSS
在本文的這一部分,我們將使用Sboxr的創建者設置的客戶端XSS playground來練習我們對客戶端XSS漏洞的檢測和利用技能。
https://domgo.at 。
概念驗證漏洞Demo。這些漏洞可用於在提交錯誤報告時創建你自己的PoC,因為它們允許讀者查看正在執行的用戶控制的數據。
練習1
1、瀏覽到https://domgo.at/ 並單擊左側窗格中的練習1,就可以使用命令行選項啟動Chrome中的第一個練習。
2、切換到Sboxr控制臺並單擊Sboxr側欄中的代碼執行
3、從HTML上下文可以看出,數據源是location.hashproperty,導致執行的接收器是HTMLElement.innerHTML
4、點擊「代碼執行」圖標將打開代碼執行詳細信息的窗口。
5、通過單擊View事件位置詳細信息的那個狙擊圖標,我們可以清楚地看到JS中我們的數據在哪裡被接收器HTMLElement.innerHTML使用。
6、為了顯示location.hash屬性是可利用的,我們通過源傳遞JS並讓它到達接收器以查看它是否已執行。
7、題目的解決方案是通過location.hash屬性傳遞<svg onload=alert(document.domain)>。最終的漏洞利用PoC是 - https://domgo.at/cxss/example/1?payload=abcd&sp=x# <svg%20onload= alert(document.domain)>
練習2
1、單擊側欄上的練習1來加載練習題目1
2、單擊側欄上的練習 - 2以加載第二個練習題目。必須通過點擊操作進入題目,而不是直接瀏覽到題目的URL,因為本練習中的源是document.referrer屬性。
3、我們按照與上一個練習相同的步驟開始,然後單擊Sboxr側欄中的「代碼執行」
4、我們從易受攻擊的代碼中看到,如果referrer的URL中有一個名為payload的參數,則將其提取並傳遞給接收器。
5、我們可以使用以下簡單的HTML頁面構建我們的漏洞。將其另存為exercise2.html並在本地託管(nginx/Apache/python/node/anything),然後通過http://127.0.0.1/exercise2.html?payload=<svg%20onload=alert(document.domain)>進行訪問。
<html>
<body>
<h2>PoC for Exercise 2 of https://domgo.at</h2>
<script>
window.location="https://domgo.at/cxss/example/2"
</script>
</body>
</html>
6、該頁面將加載並立即重定向到練習頁面,因為referrer屬性是用戶控制的代碼執行是可能的。
接下來我們來說說其他4個練習的解決方案。剩餘的練習將在我們將發布的其他文章中提到。
練習3
在許多Web應用程式中,來自外部的第三方應用程式的數據可以使用接收器,並將其作為目標應用程式的一部分,而無需清理收到的響應。在這種情況下,第三方應用程式的XHR端點可以將惡意代碼注入到目標應用程式中。即使在XHR響應來自同一站點的情況下,你也需要驗證數據在伺服器上的結果。在現代應用程式中,應用程式從不同的源收集不受信任的數據並將它們存儲在伺服器端資料庫中,最終這些不受信任的數據會進入目標應用程式,從而導致持久性的DOM XSS。
此練習涉及對JSON端點的XHR請求,該請求會將數據反射到客戶端。然後將反射的數據添加到接收器HTMLElement.innerHTML,從而執行任意代碼。
1、在「練習」頁面的文本框中輸入隨機字符串,然後單擊「執行有效載荷」的按鈕。
2、數據將由JSON端點反射到https://domgo.at/data.json?payload=thanos
3、在代碼執行窗口下使用Sboxr查看從源到接收器的數據流
4、我們可以準確地看到來自JSON響應的內容在接收器中使用並創建了一個漏洞。
5、要利用漏洞,請在文本框中傳遞字符串<img src=1 onerror=alert(document.domain)>
練習4
與XHR響應類似,受信任的websocket數據是良性的,無論它來自何處都可能導致DOM XSS問題。
此練習涉及對安全websocket端點的websocket請求,該請求將數據反射到客戶端。然後將反射的數據添加到接收器HTMLElement.innerHTML,從而執行任意代碼。
1、在「練習」頁面的文本框中輸入隨機字符串,然後單擊「執行有效載荷」的按鈕。
2、數據由wss://domgo.at/ws上的Websocket端點反射出來
3、在代碼執行窗口下使用Sboxr查看從源到接收器的數據流
4、我們可以準確地看到響應在接收器中使用的內容並創建了一個漏洞。
5、要利用漏洞,請在文本框中傳遞字符串<img src=1 onerror=alert(document.domain)>
練習5
XHR,fetch API,websockets或postMessage等通信信道經常被忽視,但最終可能會成為DOM XSS漏洞的源。特別是,如果數據來自不同的源。在響應中信任數據並通過接收器呈現/評估它可能導致DOM XSS問題,作為分析師,你必須留意這些源。
本練習涉及一個postMessage,它將用戶控制的有效載荷發送到window.onmessage事件處理程序,並將數據下沉到HTMLElement.innerHTML,執行任意代碼。
1、在「練習」頁面的文本框中輸入隨機字符串,然後單擊「執行有效載荷」的按鈕。
2、在這種情況下,數據源是來自https://domgo.at(同源)的窗口消息。
3、在代碼執行窗口下使用Sboxr查看從源到接收器的數據流
4、我們可以準確地看到響應在接收器中使用的內容並創建了一個漏洞。
5、要利用漏洞,請在文本框中傳遞字符串<img src=1 onerror=alert(document.domain)>
練習6
另一個有趣的不受信任的數據來源是瀏覽器的存儲源,包括localStorage,sessionStorage和IndexedDB。雖然攻擊者無法直接控制DOM存儲(除非應用程式中已存在XSS),但攻擊者可能能夠通過其他HTML元素或JS源將惡意數據引入存儲源。此數據最終可能會從存儲源的接收器中生成,並導致DOM XSS。
一個很好的例子就是Twitter子域上的DOM XSS - https://hackerone.com/reports/297968
在本練習中,數據源是HTML LocalStorage。頁面中的JS從localStorage讀取數據並將其傳送到HTMLElement.innerHTML,從而執行任意代碼。
1、在「練習」頁面的文本框中輸入隨機字符串,然後單擊「執行有效載荷」的按鈕。
2、在這種情況下,數據源是HTML localStorage。
3、在代碼窗口下使用Sboxr查看從源到接收器的數據流
4、我們可以準確地看到響應在接收器中使用的內容並創建了一個漏洞。
5. 要利用漏洞,請在文本框中傳遞字符串<img src=1 onerror=alert(document.domain)>
練習7
在本練習中,數據源是location.hash。但是,數據在添加到接收器HTMLElement.innerHTML之前進行處理。
1、單擊練習7並注意URL中的哈希值。
2、在代碼執行窗口下使用Sboxr查看從源到接收器的數據流
3、我們可以確切地看到location.hash數據是如何北處理的,並從那裡構建了一個漏洞。
4、從location.hash獲取值,並將HTML標記替換為其HTML實體等價物(<替換為&lt; 以及> 替換為&gt;)。然後將數據附加到<a href ='#user =並創建錨了標籤。
5、最後,數據被發送到接收器以寫入頁面,實際上是使用了我們的(假定的)構造的數據創建了錨標籤。
6、這是數據反射的HTML屬性值上下文的一個很好的例子。你可以
7、要利用這個漏洞,我們需要注入HTML屬性值的上下文並關閉懸空的單引號。可以使用對錨標籤有效的HTML事件(例如onmouseover或onclick等)觸發JS。
8、利用漏洞的URL 是https://domgo.at/cxss/example/7<abcd'%20onmouseover=alert(document.domain)%20a='
練習8
這個練習與練習7完全相同,唯一的區別是JS期望location.hash包含一個名稱值的字符串鍵值對(任何包含=字符的字符串)。
1、如果我們通過Sboxr查看JS,我們注意到通過location.hash傳遞的字符串在第一個=處被拆分,而字符串的其餘部分用於構造轉到接收器的數據(錨標籤,如上一個練習)
2、在這種情況下的漏洞利用URL是https://domgo.at/cxss/example/8<anyrandomstring=hawkeye'%20onmouseover=alert(document.domain)%20a='
練習9
本練習使用兩個源location.hash和window.name處理來自這些源的數據,然後將其發送到HTMLElement.innerHTML 接收器。
1、單擊練習9並注意包含哈希值user=12345的URL
2、在這種情況下有兩個來源。最終發送到接收器HTMLElement.innerHTML的數據是從兩個源獲得的。
3、查看代碼執行細節,很明顯,來自location.hash的數據在=符號處被分割,然後只選擇前10個字符並將其附加到window.name中的數據。此外,在被附加到window.name中的數據之前,通過使用等效的HTML實體來清理出現的雙引號。
4. 為此寫一個漏洞EXP就意味著
· 通過location.hash傳遞10個字符但不能出現雙引號(我們顯然不能使用元素屬性注入,因為我們無法突破href屬性)
· 通過window.name傳遞JS的其餘部分,並讓易受攻擊的JS將它們都附加到一起,最後就產生出我們想要的漏洞EXP
· 我們不能突破href屬性,因為我們已經在href中,我們可以使用javascript:protocol handler來點擊錨標籤來觸發我們的代碼
· 本質上,我們是利用了javascript:alert(document.domain)作為我們的PoC。
5. 創建包含以下代碼的HTML頁面,將其託管在本地伺服器上並在瀏覽器中打開它。
<html> <body onload=exploit()> <h2>PoC for Exercise 9 of https://domgo.at</h2> <script> function exploit() { var win = window.open("https://domgo.at/cxss/example/9#a=javascript", ":alert(document.domain)", ""); } </script> </body></html>
6.大多數現代瀏覽器可能會使用內置的彈出窗口阻止程序啟動阻止新窗口,但你必須允許這樣做。如果你想擺脫彈出警告,你可以修改HTML PoC以觸發用戶驅動事件(如滑鼠點擊等)上的window.open。
<html> <body> <h2>PoC for Exercise 9 of https://domgo.at</h2> <label onclick="exploit()">Click me for solution to Exercise 9</label> <script> function exploit() { var win = window.open("https://domgo.at/cxss/example/9#a=javascript", ":alert(document.domain)", ""); } </script> </body></html>
7. 一旦你啟動新窗口後,單擊Welcome消息就會執行我們的有效載荷。
練習10
這與練習9類似,但JavaScript除外,其中的代碼路徑是基於條件分支執行的。使用手動測試很容易遺漏這一點,因為僅當滿足JS中的某些代碼條件時,接收器才會填充我們的惡意數據。
在本練習中,我們通過兩個來源location.href和window.name傳入數據,在滿足分支條件和一些簡單的處理之後就可以將其傳遞到HTMLElement.innerHTML 接收器。
客戶端JS中可能存在條件分支代碼,這可能會使創建有效的漏洞EXP變得有點困難。此練習顯示了如何檢測條件分支並傳遞正確的字符串,以便可以訪問接收器並執行攻擊者的代碼。
1、如果我們查看來自源的數據流,我們會看到來自location.href和window.name的數據被附加在一起。
2、可以使用window.open()使用我們的數據設置window.name中的數據。在本地伺服器上託管以下內容並在瀏覽器中打開它。在瀏覽器提示時啟用瀏覽器的彈出窗口。
<html> <body onload=exploit()> <h2>PoC for Exercise 10 of https://domgo.at</h2> <script> function exploit() { var win = window.open("https://domgo.at/cxss/example/10?lang=en&user=ID-12345&returnurl=/", ":alert(document.domain)", ""); } </script> </body></html>
3、在代碼執行詳情窗口中,我們看到來自location.href屬性的數據在ID-之後被拆分,剩下的字符串被處理為雙引號並附加到了window.name的值裡面。
4、我們可以查看源進行檢查條件分支。在這個例子中不是很明顯,因為我們在URL中的用戶參數已經以ID-開頭,但情況可能並非總是如此。單擊目標符號會顯示JS的原始碼,如果用戶參數以ID-開頭,很明顯會到達接收器。
5、根據我們現在的情況,我們的漏洞利用只需通過導航到https://domgo.at/cxss/example/10?lang=en&user=ID-javascript&returnurl=/,在同一個窗口中生成 HTML代碼,然後單擊welcome href錨標籤即可成功利用漏洞。
結論
Sboxr是一個非常強大的工具,可以與其他Web應用程式攻擊工具(如Burp和ZAP)結合使用,尤其是在使用富JavaScript的應用程式時。源和接收器之間的數據流以及準確顯示數據傳輸和修改方式的能力使得此工具在你的工具庫中非常有用。
使用該工具,我們完成了10個練習的解決方案。對於嘗試學習客戶端XSS的挖掘和利用的人,建議使用本文所描述的這些東西。
參考文獻:
1、Sboxr — https://sboxr.com
2、客戶端XSS漏洞 - https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting#DOM_Based_XSS_.28AKA_Type-0.29
3、命令行開關 - https://dev.chromium.org/developers/how-tos/run-chromium-with-flags
4、XMLHttpRequest(XHR)MDN - https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
5、window.postMessage()MDN - https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
6、https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API
7、https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
8、https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API
9、HTML 實體字符- https://dev.w3.org/html5/html-author/charref