HACK TEH BOX - Under Construction(JWT密鑰混淆 + SQL注入)
1. JWT密鑰混淆
JWT的組成一般分為三部分,{算法}.{payload}.{簽名},例如加密函數中jwt.sign(data, privateKey, { algorithm:'RS256' })中,data為數據,privateKey為加密密鑰,{ algorithm:'RS256' }為加密算法,JWT的一般形式和組成如下圖所示。

JWT常用的兩種算法是RSA和HMAC,分別是非對稱算法(一對密鑰)和對稱算法(一個密鑰)。RS256算法在服務端利用私鑰進行加密,利用公鑰來進行解密驗證數據。HS256算法只擁有一個密鑰,用於加密和解密。考慮一種情況,如果在解密的過程中,解密的算法被偽造,由RS256更改為HS256,那么被用於HS256解密的密鑰就變為RS256中的公鑰,而由於公鑰的性質,可能會被攻擊者獲取,攻擊者在獲取到RS256的公鑰后,使用公鑰作為密鑰,利用HS256算法進行加密,當JWT值發送給服務端時,會被以HS256的方式進行解密,而解密的密鑰也是RS256公鑰,這樣攻擊者就可以偽造JWT中的payload值。
下圖為題目中存在漏洞的代碼,作為示例來介紹該漏洞

示例代碼中,加密過程使用的是RS256算法,利用私鑰進行加密,但是在解密的函數中,同時提供了兩種算法選項,這就表示如果使用HS256算法進行解密,依然是使用公鑰作為密鑰,存在該漏洞。
2. 環境
Hack The Box生成 Challenge環境(206.189.121.131:30520) 
參考代碼一份,包含內容如下

3. Challenge
首先去環境看一下 
一個簡單的登錄頁面,注冊一個admin/123456的賬戶,再使用該賬戶登錄,登陸后頁面跳轉
注冊請求: 
登錄請求,返回JWT: 
登陸成功,頁面跳轉: 
登錄頁面進行簡單的sql注入測試后,未發現注入點,F12瀏覽一下網站內信息,沒有js文件被加載,登錄后被分配一個JWT值 
拿去Burpsuite里解密一下看看內容 
RS256算法,非對稱加密,但是在payload部分發現了公鑰信息
寫個簡單腳本使用公鑰來解密一下信息 
運行成功,即JWT里面的公鑰正確 
目前就能獲取到這么多信息了,結合JWT內的公鑰信息,可以大概猜出是利用JWT作為突破點進行攻擊
接下來去看一下Challenge提供的網站源碼,看有沒有什么有用的信息
先去看看/routes/index.js路由文件

整個路由包含了以下幾個部分
1.GET請求/
2.GET請求/auth
3.GET請求/logout
4.POST請求/auth
這四個部分的功能都非常的簡單,POST請求根據register字段的值判斷登錄/注冊,/logout清除session值,/auth返回auth.html頁面,在GET請求/時,需要先通過JWT內的值判斷用戶是否存在,再進行頁面跳轉或錯誤信息,判斷過程首先要執行AuthMiddleware函數,返回成功后再執行DBHlper.getUser(username)函數,如果username在數據數據庫中存在的話,就會跳轉至index.html頁面,也就是登錄后看到的頁面了。
順着這個順序,首先先去看看AuthMiddleware.js文件 
大概功能就是返回JWT解碼后的username值,然后這個值就會被拿去DBHlper.getUser(username)函數比對
接着去JWTHelper.js文件 
就是一個簡單的JWT加解密,但是在解密的過程中,同時支持了兩種算法RSA256/HS256,這個地方就暴露出了漏洞——JWT密鑰混淆
在進行完AuthMiddleware函數的流程后,進行下一步DBHlper.getUser(username) 
在這個代碼中,第一個sql語句使用了拼接字符串的形式,后面的sql語句則是傳遞參數的形式,存在sql注入的漏洞
到這里就可以確定整個題目的思路了,首先GET請求/時,攜帶利用公鑰偽造的JWT,而JWT中的username字段值為sql注入語句,執行后就可以進入數據庫查找flag了。
4. Walkthrough
寫腳本利用公鑰作為密鑰進行HS256加密 
報錯 
查看源碼,發現被禁止使用公鑰來加密 
直接去掉 
在執行,返回值 
拿着這個值去GET請求/驗證 
驗證成功,返回index.html頁面,此時可以構造username字段進行sql注入
接下來結合JWT,寫一個sqlmap的tamper腳本 
大概思路就是cookie值作為注入點,然后將payload寫進username字段再進行加密作為cookie值傳遞
tamper腳本實現的過程只需要修改輸入參數payload,然后輸出retVal即可,如下圖所示

執行代碼時同樣報錯 
改掉

測試代碼輸出成功,接下來進行腳本編寫 
寫好 
上sqlmap測試

拿到flagHTB{d0n7_3xp053_y0ur_publ1ck3y}
