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}