基础知识
jwt是由三部分构成的,第一部分是头部(header),第二部分是载荷(payload),第三部分为签证(signature)
头部
头部声明了类型和加密方法,如下
{
'typ': 'JWT',
'alg': 'HS256'
}
然后将头部进行base64加密后去掉=号,构成第一部分
ewogICd0eXAnOiAnSldUJywKICAnYWxnJzogJ0hTMjU2Jwp9
载荷
和头部结构类似,但存放的是数据
签证
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
header (base64后的)
payload (base64后的)
secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后
payload示例
{
"sub": "1234567890",
"name": "John Doe"
}
标准中注册的声明 (建议但不强制使用)
# iss: jwt签发者
# sub: jwt所面向的用户
# aud: 接收jwt的一方
# exp: jwt的过期时间,这个过期时间必须要大于签发时间
# nbf: 定义在什么时间之前,该jwt都是不可用的
# iat: jwt的签发时间
# jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
web345
F12发现/admin,访问后抓包发现cookie后跟着jwt的值
auth=eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2MzI2MjI1ODksImV4cCI6MTYzMjYyOTc4OSwibmJmIjoxNjMyNjIyNTg5LCJzdWIiOiJ1c2VyIiwianRpIjoiZDNlYjRlZTgyMThjMmNmZTVlMGQxMjM5MjNlNDc0M2EifV0
base64解码后得到
{"alg":"None","typ":"jwt"}[{"iss":"admin","iat":1632622589,"exp":1632629789,"nbf":1632622589,"sub":"user","jti":"d3eb4ee8218c2cfe5e0d123923e4743a"}]
将sub的值改为admin后,在进行base64加密
{"alg":"None","typ":"jwt"}[{"iss":"admin","iat":1632622589,"exp":1632629789,"nbf":1632622589,"sub":"admin","jti":"d3eb4ee8218c2cfe5e0d123923e4743a"}]
传给auth后得到flag
web346
在/admin抓包后得到jwt值
eyJhbGciOiJOb25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYzOTAyNDY4NCwiZXhwIjoxNjM5MDMxODg0LCJuYmYiOjE2MzkwMjQ2ODQsInN1YiI6ImFkbWluIiwianRpIjoiMzU4ZmVhZmI5YjdjZjViZWExYjlmODQyYjVkMWJhNmIifQo=
使用在线工具解密后得到
jwt在线工具
猜测密码是123456修改sub的值(不知道为什么明明密码很简单但是jwtcrack却跑不出来)
传参得到flag
web347
同上密码还是123456
web348
/admin目录抓包得到jwt值
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYzOTAyNjQ4NiwiZXhwIjoxNjM5MDMzNjg2LCJuYmYiOjE2MzkwMjY0ODYsInN1YiI6InVzZXIiLCJqdGkiOiJhYjkzNjNkZGM2MDhjODk3NTI0MTMyYTM4NjE3OTk4MCJ9.fkXIROeG08zyykg9u0PnqkJ4VvYv39f3zwkLjXce8FA
用jwtcrack爆破密码,得到密码aaab
修改密码和sub值
传参得到flag
web349
打开源码访问发现public.key和private.key,访问后得到公私钥
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');
}
});
});
抓包得到jwt的值,jwt.io解码后得到RS256加密
{
"alg": "RS256",
"typ": "JWT"
}
{
"user": "user",
"iat": 1609250966
}
将payload中的user改为admin,把私钥和公钥复制进Verify Signature即可得到我们需要的auth的值。传参即可得到flag