神奇的题,使我的大脑旋转


这俩界面试过了啊
sql注入和ssti没啥用,不信可以试试,然后告诉我怎么写(请务必这样做)
所以开始看看源码
发现了css和js
一个个点进去看了,发现在app.js里有个东西

然后?然后就卡住了
我知道需要进入/api/flag但是我进不去啊
所以去查找一下
发现是koa框架
koa框架
koa是一个基于node实现的一个新的web框架,它是由express框架的原班人马打造的。它的特点是优雅、简洁、表达力强、自由度高。它更express相比,它是一个更轻量的node框架,因为它所有功能都通过插件实现,这种插拔式的架构设计模式,很符合unix哲学。
emm
暂时别过多了解,脑子烂,会炸
可以先了解一下它的源码结构/文件框架

所以,我们使用常见框架去获取一下控制器文件
发现源代码
const crypto = require('crypto'); const fs = require('fs') const jwt = require('jsonwebtoken')
const APIError = require('../rest').APIError;
module.exports = { 'POST /api/register': async (ctx, next) => { const {username, password} = ctx.request.body;
if(!username || username === 'admin'){ throw new APIError('register error', 'wrong username'); }
if(global.secrets.length > 100000) { global.secrets = []; }
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'});
ctx.rest({ token: token });
await next(); },
'POST /api/login': async (ctx, next) => { const {username, password} = ctx.request.body;
if(!username || !password) { throw new APIError('login error', 'username or password is necessary'); }
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'});
const status = username === user.username && password === user.password;
if(status) { ctx.session.username = username; }
ctx.rest({ status });
await next(); },
'GET /api/flag': async (ctx, next) => { if(ctx.session.username !== 'admin'){ throw new APIError('permission error', 'permission denied'); }
const flag = fs.readFileSync('/flag').toString(); ctx.rest({ flag });
await next(); },
'GET /api/logout': async (ctx, next) => { ctx.session.username = null; ctx.rest({ status: true }) await next(); }
|


两个重点列出来
一个是有关username和password生成jwt
一个是读取flag的
我们发现username要等于admin
登录验证则是jwt
所以我们应该对于jwt进行破解
并且是通过hs256加密,我们需要改为加密方式改为none来进行破解
标题中的alg字段更改为none,有些JWT库支持无算法,即没有签名算法。当alg为none时,后端将不执行签名验证。 此外对于本题中验证采用的密匙secret值也需要为空或者undefined否则还是会触发验证,所以将JWT中secretid项修改为[]。
所以,我们需要改变的是
alog、username、secrettid
我们先进行抓包

那大概率就是说authorzation那个就是我们的jwt的值(因为也是验证身份的,应该是一起上传的)
去解密一下

拿到了一些重要的信息比如iat
然后写脚本生成新的jwt

生成了一串东西
也就是你的新authorization
之后在登录的时候抓个包修改一下

我们就可以以admin的用户进入
之后再查询api/flag路径即可