Juice Shop Write-up (整理過後版) === --- ###### tags: `JuiceShop` `CTF` `security` `Web` 依照題目類型整理 有些 Write-up 或許可能Maybe會有先後順序的問題 所以我依舊會優先更新流水帳版本的 write-up 再更新這篇 流水帳版本 Write-up: https://hackmd.io/@LJP/HktxnOpR4 --- [TOC] # XSS ## XSS Tier 0 ``` <iframe src="javascript:alert(`xss`)"> ``` 以上打在 Track Orders 中 ![](https://i.imgur.com/trQm8Ai.png) ## XSS Tier 1 ``` <iframe src="javascript:alert(`xss`)"> ``` 以上打在 Search 中 ![](https://i.imgur.com/xGuY7eI.png) ## XSS Tier 1.5 Set Username 中有套某些 RegEx,導致某種長相的字串會被取代 中間不小心試到一個 整個爆掉 = = ![](https://i.imgur.com/li47ULc.png) 中間嘗試了很多 pattern 以下列著比較有意義的嘗試 | Before | After | -------- | -------- | | `<script>alert(`\``xss`\``)</script>` | `lert(xss)</script>` | | `<</abcd>/abcd>` | `</abcd>` | | `<<abcd>efgh>` | `<fgh>` | | `<<a>efgh>` | `<fgh>` | | `<<a>ascript>` | 頁面炸裂,`<script>` | | `<<a>ascript></script>` | `<script></script>` | | `<<a>ascript>alert(`\``xss`\``)</script>` | `<script>alert(`\``xss`\``)</script>` | 用最後一筆 pattern 就成功囉~ ## XSS Tier 2 > Perform a persisted XSS attack with \<iframe src="javascript:alert(\`xss\`)"\> bypassing a client-side security mechanism. persisted 的欄位,一開始直覺就是商品底下的 comment,但是踹 comment 沒有成功 回頭想想 persisted 的欄位、其他 User 看得到的, J個嘛...... 腦筋動到 User 本身上 - ~~User 名稱~~ (只能在自己的帳號管理頁面看到) - User Email (admin 在主控台看得到,在 comment 中也會顯示) User 名稱踹踹看,繼承 XSS Tier 1.5 嘗試中有些 RegEx 要閃 ``` <<a>aiframe src="javascript:alert(`xss`)"> ``` WoW ![](https://i.imgur.com/Zhc4CcJ.png) (噢對了 我頭像有亂改過) 然後玩到這裡才突然想到,comment 中顯示的不是 Username 而是 email 果斷放棄改 Username 改踹 Email,可是 Email 在註冊時就決定了,所以只能踩看看註冊API了 不過這次硬把 Register Button Enable 起來,也送不出 Request 好吧,只好攔截爆改了 把 Email 改成 ``` <iframe src='javascript:alert(`xss`)'> ``` ![](https://i.imgur.com/8NY9178.png) ![](https://i.imgur.com/kxIyCeK.png) 唉呦 可以ㄛ 試試看登入,發現糗了 ![](https://i.imgur.com/ixdEjWP.png) 登不進啦乾 but 還可以從 admin 頁面看到這個 email ![](https://i.imgur.com/dBqZhpQ.png) 一進來就 xss,表示真的成功了 ![](https://i.imgur.com/exIXDKh.png) 阿可是這題沒解開,該不會是一定要打以下吧? ``` <iframe src="javascript:alert(`xss`)"> ``` 沒關係就來試試看 因為參數結構是 ``` "email":"<blablabla...>" ``` 要閃雙引號,所以改成如下 ![](https://i.imgur.com/Lz1Aa9F.png) 欸,一送出去,連驗證 xss 有沒有成功都不用就解這題了 ![](https://i.imgur.com/bDlXFqW.png) # Broken Access Control ## Five-Star Feedback 進入 administration 後 砍掉五星評價 over ## Basket Access Tier 1 觀察按下去 Your Basket 後會發送什麼封包 ![](https://i.imgur.com/RomzCCJ.png) ![](https://i.imgur.com/rUXDzaO.png) 看到 Request URL: `http://192.168.124.141:3000/rest/basket/3` 3 是我現在登入的帳號的編號 很好,直接用 burpsuite 改改看那個數字 ![](https://i.imgur.com/aNMCtAc.png) 改成 4 看看 就拿到帳號編號為 4 的 basket 了 以下這張為沒有竄改封包 本人的basket ![](https://i.imgur.com/EKCnJT4.png) 以下這張為帳號編號為 4 的 basket ![](https://i.imgur.com/EkbGzsC.png) 也解這題了 ## Admin Section 用 `admin@juice-sh.op' -- ` 登入後 再進 administration 就解這題了 ![](https://i.imgur.com/q6p6jt6.png) ## Forged Review 既然 basket 都能亂存取到其他帳號的 basket 那麼其他功能是否也能亂存取到其他帳號的呢 e.g. 留言 按讚 結帳 留言的更改 是打以下 request: ![](https://i.imgur.com/mYXKXlL.png) Method 為 PATCH API 在 /rest/product/reviews id 推測為該留言的 id, message 為更改的內容 馬上來試改其他留言看看 先來查看隨便其中一個 product 的 review ![](https://i.imgur.com/8oV3Neq.png) 得到id,來改看看封包,先編輯自己的留言,並用burpsuite攔截下來 ![](https://i.imgur.com/rDaILRE.png) 把id改掉 ![](https://i.imgur.com/SgOSEix.png) 成功爆改並解題 ![](https://i.imgur.com/grjLxK3.png) cool ## Forged Feedback 主要是這個頁面 ![](https://i.imgur.com/8rJ9DPM.png) 用 Network 看了一下執行流程 1. 先 GET http://192.168.124.137:3000/rest/captcha/ 取得一筆 json 內容為 answer, captcha, captchaId ![](https://i.imgur.com/ktgEeqh.png) 2. POST 到 http://192.168.124.137:3000/api/Feedbacks/ POST 的欄位分別為 captcha, captchaId, comment, rating ![](https://i.imgur.com/sf7fPkr.png) 寫了個 python 壓力測試 ```python= import requests import json host = "192.168.124.137:3000" captcha_url = "http://" + host + "/rest/captcha/" feedback_url = "http://" + host + "/api/Feedbacks/" for i in range(50): resp = requests.get(captcha_url) data = resp.json() postdata = {'UserId': 1, 'captcha': str(data['answer']), 'captchaId': data['captchaId'], 'comment': "YEEEEE", 'rating': 0 } r = requests.post(feedback_url, data = postdata) ``` 就解ㄌ ## Basket Access Tier 2 我在想能不能隨便幫其他 user 亂加東西到購物車 首先,先觀察加進購物車的流程 ![](https://i.imgur.com/yaLrYR3.png) ![](https://i.imgur.com/sTWh7Db.png) 看來關鍵是這個API: POST `http://192.168.124.141:3000/api/BasketItems/` BasketId 為要加進的 Basket ProductId 為產品 quantity 為數量 好像很簡單 馬上攔截下來爆改看看 ![](https://i.imgur.com/K76Advd.png) ![](https://i.imgur.com/6HboENG.png) 欸欸欸 無效 BasketId ? 那我改成登入 admin,然後硬給 BasketId 3 加咚咚試試看 ![](https://i.imgur.com/ahv3UrP.png) 結果還是一樣 那還是我刻意忽視掉的 API: ![](https://i.imgur.com/gxASFG8.png) GET `http://192.168.124.141:3000/rest/basket/1` 是有作用的? 就是其實他有先打 GET rest/basket/{BasketId} (或有可能是 UserId) 再打 POST api/BasketItems 這次爆改 要連第一個GET都不放過試試看 登入admin,亂加購物車,攔截下來改: ![](https://i.imgur.com/MvsEhV4.png) 結果一樣不行 那會不會是,真的有判斷登入者是誰? 不過經過一番研究後 發現 如果我的 basket 中已經有一個商品 再按一次加入購物車 會呼叫這個 API ![](https://i.imgur.com/giDdE0M.png) 這個商品在我的購物車中 原先已經有了10個 感覺是JS運算給他 +1 並打這個 Request 過去修改數量 我先測試看看 這個數量是否是能修改的 ![](https://i.imgur.com/WCXKAn6.png) ![](https://i.imgur.com/Nh3aZmQ.png) OK 看來後端沒檢查值一定要是剛好 +1 過後的 這個API是這樣 PUT `http://192.168.124.141:3000/api/BasketItems/8` quantity 是數量 網址列中 最後的數字 8 應該是指 BasketItemId 已知 id = 8 的 BasketItem 是屬於 admin 的 現在就來登入其他帳號,並且試著透過這個API來修改這 id = 8 的 BasketItem 的 quantity 原先封包 ![](https://i.imgur.com/fzyQ40v.png) 改成 ![](https://i.imgur.com/X5uKqHR.png) 好像修改成功了 ![](https://i.imgur.com/GHQSPqt.png) ![](https://i.imgur.com/EAEbhIs.png) BananaJuice 變 50 個啦 但我終極目的是要幫其他 user 亂加東西進購物車餒 我在想 打 POST api/BasketItems 這API 我竄改後,他Response是401 真的要登入的話 就要幹 cookie 或是 session ~~好麻煩~~ 最後放棄 Google 了 Write-up 看到結果後 還好我放棄了 ![](https://i.imgur.com/VvAEsU2.png) 原來有這種東西 長知識了! 馬上來玩玩看 ![](https://i.imgur.com/KPOfiJp.png) Response: ![](https://i.imgur.com/ppkQrqr.png) 成功把它加進其他user的購物車!!! 太神啦!!! 成功解掉這題 cool # Injection ## Login Admin 再回來看看登入介面 嘗試看看 SQL Injection ![](https://i.imgur.com/FB71RoR.png) 回傳了... ![](https://i.imgur.com/KgJPW7a.png) 所以若我知道 admin 的信箱是啥 而且輸入的部分沒有檔 '--' 或 '#' 就可以直接 injection 登進去 就先用看看 `' or 1=1 --` 就登入進去了 ## Login Jim 用 `jim@juice-sh.op' -- ` 登入就解了 over ## Login Bender 用 `bender@juice-sh.op' -- ` 登入就解了 over # Race Condition # Insecure Deserialization # Vulnerable Components # Sensitive Data Exposure ## Confidential Document 進去 About Us 後,看到一個 Check out our boring terms blablabla.... ![](https://i.imgur.com/NuovJLg.png) 進去後是長這樣 ![](https://i.imgur.com/hqg1iD0.png) 看看目錄有沒有設定讀取保護 ![](https://i.imgur.com/XnbvjmL.png) 耶 看來是沒有 ㄎㄎ ![](https://i.imgur.com/90MPM0m.png) 可是有保護說副檔名要是 .md 或 .pdf 就先踩踩這個 md ㄅ ![](https://i.imgur.com/tMQLHQd.png) 就又解一題了 (???? ## Weird Crypto 這題題目寫說,透過 Contact Us 告訴 Server 一個被誤用的 Algorithm 或 Library 我是回傳 md5,不過理由是 logout 那邊會用 md5 hash 密碼並傳回來,而這件事情不應該發生 官方 write-up 對於 md5 是個答案的原因這樣寫: > Passwords in the Users table are hashed with unsalted MD5 > 我的理解是,密碼以 unsalted MD5 hash 過再存回資料庫,但照理說應該要加一些料,讓他不是單純的 MD5 不過以黑箱的角度,能觀察到這件事情嗎? 除非我能 SQL Injection 直接 dump 整個 database 出來看,才能知道這件事吧 但其實不用,在登入頁面時,觸發 SQL 錯誤,會回傳整個 SQL Statement ![](https://i.imgur.com/ixdEjWP.png) 那個 password 可以自行驗證一下,的確只是 md5 hash 過而已 得證資料庫中,Table Users 中的 password 為 unsalted md5 hash ## Login MC SafeSearch 這題看了一下提示,聽了一下 先登入了 admin 看了一下 email 是 `mc.safesearch@juice-sh.op` 再來登看看就登入ㄌ # Security Misconfiguration ## Error Handling 不知道怎樣 莫名其妙解了 好像是隨便造成 server 的 error 都可解這題 我是有亂踩 SQL Injection 測試 ## Forgotten Sales Backup 同 Easter Egg Tier 1 # Broken Authentication ## Password Strength 研究一下 logout API: ![](https://i.imgur.com/toYJPk7.png) Return: ![](https://i.imgur.com/S12og6W.png) 其中密碼是32個16進制組成的 讓人聯想到,是否原本密碼會以某種 128bits(32 * 4) 加密法加工並且回傳 若以未登入之姿進入這個API ![](https://i.imgur.com/3L7uOxg.png) 嗯,沒搞頭。 在其他題時就已經能登入 admin 了 看看 admin 登出後,那個看似 hash/encrypt 過的密碼長怎樣 ![](https://i.imgur.com/GCclC4m.png) ``` email admin@juice-sh.op password 0192023a7bbd73250516f069df18b500 ``` 128bits hash algorithms 有 MD5 測試看看線上破解網站 ![](https://i.imgur.com/RsLqjqd.png) well 一個弱密碼 `admin123` 用原本的帳密登入 就解這題了 # Security through Obscurity ## Score Board 在一開始 Load 網頁時就監控 Network ![](https://i.imgur.com/NoGxhx8.png) 發現有一個特別牛逼 ![](https://i.imgur.com/kuX2G9q.png) 看看內容是什麼 ![](https://i.imgur.com/uzkjTF1.png) 後來閒閒沒事又把其他咚咚看了 ![](https://i.imgur.com/Nyjf7UN.png) 看得了關鍵的 URL: /#/score-board 連進去看看 就解開這題了 ## Easter Egg Tier 2 繼承 Easter Egg Tier 1 當時是猜用凱薩密碼加密 用網站 brute-force 了一下 ![](https://i.imgur.com/jVvGiN5.png) ``` /gur/qrif/ner/fb/shaal/gurl/uvq/na/rnfgre/rtt/jvguva/gur/rnfgre/rtt /THE/DEVS/ARE/SO/FUNNY/THEY/HID/AN/EASTER/EGG/WITHIN/THE/EASTER/EGG ``` 該不會這是一個路徑吧 ![](https://i.imgur.com/i44rGYP.jpg) **WOW靠!! 是怎樣 這星球還會動** 造訪了這顆星球後,這題就解了 # XXE # Forgotten Content # Roll your own Security ## Privacy Policy Tier 1 privacy-security 頁面進去就解這題了 ![](https://i.imgur.com/zVvT90y.png) ## CAPTCHA Bypass Tier 1 Forged Feedback的解法 可以一起把這題解掉 ## Forgotten Developer Backup ㄜ 我想故技重施(參見 Easter Egg Tier 1) 把整個 FTP 看到的都載下來 就也解這題ㄌ ## Easter Egg Tier 1 繼承上面 結果不知道為啥 incident-support.kdbx 可以下載!???!? ![](https://i.imgur.com/8nyGNKA.png) 注意下方 我把它 download 下來了 用 notepad++ 開 ![](https://i.imgur.com/NgwAJe1.png) well, 我還是用 binwalk 看看他是啥好了 ![](https://i.imgur.com/ljIODUm.png) 結果啥都不是@@ 好不重要,重要的是,我知道還是有辦法下載下來的 但後來餵狗後 發現我思考方式好像錯了 原本我想說 找找 GET .kdbx 與 GET 其他檔案 打的封包有什麼不同 後來發現更牛逼的方式 ![](https://i.imgur.com/Nq6MqH2.png) 用 Burpsuit 攔截封包 ![](https://i.imgur.com/lsiKVxm.png) 把第一行的 GET 改成 ``` GET /ftp/eastere.gg%00.md HTTP/1.1 ``` 看看 欸豆 不行 ![](https://i.imgur.com/PI1ohaH.png) 後來再查了一下,發現連 % 都要用URL Encoding 所以 % 要改成 %25 ![](https://i.imgur.com/XM3gHxP.png) 耶~~ 下載下來ㄌ 內容長醬子 ![](https://i.imgur.com/XKmhEDs.png) 那個一臉 Base64 樣的字串 ``` L2d1ci9xcmlmL25lci9mYi9zaGFhbC9ndXJsL3V2cS9uYS9ybmZncmUvcnR0L2p2Z3V2YS9ndXIvcm5mZ3JlL3J0dA== ``` 解碼後變成 ``` /gur/qrif/ner/fb/shaal/gurl/uvq/na/rnfgre/rtt/jvguva/gur/rnfgre/rtt ``` 欸先等等 已經解一題了 (不得不說 解題解的莫名其妙的 先記一下感覺,這解碼後的東東,可能可以試試看凱薩 ## Misplaced Signature File 同 Easter Egg Tier 1 # Improper Input Validation ## Zero Stars 硬把 Submit button 的 disable 取消 就可以發送 0 星評價ㄌ ## Repetitive Registration ![](https://i.imgur.com/F8L6eeE.png) 砍掉 disable ![](https://i.imgur.com/muKtkj3.png) 來送一個 `password` 跟 `passwordRepeat` 欄位不一樣的 Request 試試看 ![](https://i.imgur.com/cmqr7VX.png) 可以註冊,表示重複密碼這件事情只有在前端有檢查,後端卻沒擋掉。