3. About Me
PentesterLab.com / @PentesterLab
Security Engineer:
PentesterLab:
Pentester/Code Reviewer/Security consultant/Security architect
Platform to learn web security/penetration testing
100% Hands-on
Available for individuals (free and PRO) and enterprises
Run a website to help people learn security
4. JOSE/JWE/JWS/JWT
PentesterLab.com / @PentesterLab
• JOSE:
• Javascript Object Signing and Encryption
• Also the name of the working group
• JWT: JSON Web Token == “jot” Token
• JWE: JSON Web Encryption
• JWS: JSON Web Signature
• JWK: JSON Web Key
• JWA: JSON Web Algorithm
5. Who uses JWT
PentesterLab.com / @PentesterLab
• A lot of people for OAuth
• A lot of people for sessions
• A lot of people to manage trust
• A lot of people for password reset
• A lot of people who care about being stateless
and multi-datacenter architecture
7. JavaScript Object Notation (JSON)
PentesterLab.com / @PentesterLab
Human readable format to store or transmit objects
8. The Compact JWS Format
PentesterLab.com / @PentesterLab
Header Payload Signature
3 parts in a JSON Web Token:
9. The Compact JWS Format
PentesterLab.com / @PentesterLab
Header Payload Signature
Separated by a dot
. .
10. The Compact JWS Format
PentesterLab.com / @PentesterLab
eyJ0eXAiOiJK
V1QiLCJhbGci
OiJIUzI1NiJ9
eyJsb2dpbi
I6ImFkb
WluIn0
FSfvCBAwypJ4abF6
jFLmR7JgZhkW674
Z8dIdAIRyt1E
Separated by a dot
. .
eyJ = Base64('{"')
11. The Compact JWS Format
PentesterLab.com / @PentesterLab
Base64({…}) Base64({…}) Base64(…)
Header and Payload are base64* encoded JSON
. .
* urlsafe base64 encoding without padding
The signature is also base64 encoded
12. The Compact JWS Format: Encoding
PentesterLab.com / @PentesterLab
Urlsafe base64 encoding without padding:
*https://tools.ietf.org/html/rfc7515#appendix-C
13. The JWT Format: header
PentesterLab.com / @PentesterLab
Base64({"alg": "HS256",
"typ": "JWS"})
The header contains an algorithm “alg” attribute:
In this example HMAC with SHA256 was used
To tell how the token was signed.
…
. . …
14. The JWT Format: Algorithms
PentesterLab.com / @PentesterLab
A lot of different algorithms are supported*:
None
* https://jwt.io/ covers most
HS256
HS384
HS512
RS256
RS384
RS512
ES256
ES384
ES512
PS256
PS384
PS512
15. The JWT Format: Algorithms
PentesterLab.com / @PentesterLab
Scenario: one client talking to multiple services
16. The JWT Format: Algorithms
PentesterLab.com / @PentesterLab
HS256
HS384
HS512
HMAC: All services need to know the secret
17. The JWT Format: Algorithms
PentesterLab.com / @PentesterLab
HS256
HS384
HS512
HMAC: if one service gets compromised
18. The JWT Format: Algorithms
PentesterLab.com / @PentesterLab
HS256
HS384
HS512
HMAC: the secret is compromised for all services
19. The JWT Format: Asymmetric
PentesterLab.com / @PentesterLab
RS256
RS384
RS512
ES256
ES384
ES512
PS256
PS384
PS512
Asymmetric: sharing the key
Private
Public
20. The JWT Format: Asymmetric
PentesterLab.com / @PentesterLab
RS256
RS384
RS512
ES256
ES384
ES512
PS256
PS384
PS512
Asymmetric: Only trusted services get the
private key
Private
Public
21. The JWT Format: Asymmetric
PentesterLab.com / @PentesterLab
RS256
RS384
RS512
ES256
ES384
ES512
PS256
PS384
PS512
Asymmetric: If one service gets compromised…
Private
Public
22. The JWT Format: Asymmetric
PentesterLab.com / @PentesterLab
RS256
RS384
RS512
ES256
ES384
ES512
PS256
PS384
PS512
Asymmetric: Even in the browser!
Private
Public
23. The JWT Format: payload
PentesterLab.com / @PentesterLab
…
The payload may contain literally anything:
Base64({"user":"admin",
"roles": ["adm","users"]}). . …
24. The JWT Format: payload
PentesterLab.com / @PentesterLab
The payload may contain registered claims:
Base64({"user":"admin",
"exp":12…, "iat":1234.. }). .… …
25. The JWT Format: payload
PentesterLab.com / @PentesterLab
The payload may contain registered claims:
• “iss”: issuer
• “sub”: subject
• “aud”: audience
• “jti”: claim id
• “exp”: expiration time
• “nbf”: not before
• “iat”: issued at*
* useful for async processing
26. The JWT Format: creating a token
PentesterLab.com / @PentesterLab
• Create the JSON header and base64 encode it
• Create the JSON payload and base64 encode it
• Concatenate with a dot the (encoded) header
and payload
• Sign the result (header+.+payload)
• Base64 encode the signature
• Append a dot then the signature
27. The JWT Format: verifying a token
PentesterLab.com / @PentesterLab
• Split the token in three parts based on the dots
• Base64 decode each part
• Parse the JSON for the header and payload
• Retrieve the algorithm from the header
• Verify the signature based on the algorithm
• Verify the claims
28. Keep in mind
PentesterLab.com / @PentesterLab
• Multiple systems can issue tokens
• A token can be used by multiple systems
• All these systems can use different libraries
30. By design: verifying signature
PentesterLab.com / @PentesterLab
Base64({ "alg": "HS256",
"typ": "JWS"})
You need to base64 decode and parse
JSON to verify the signature:
Larger attack surface
JSON.load vs JSON.parse, Base64 decoding
…
. . …
31. By design: verifying signature
PentesterLab.com / @PentesterLab
The attacker controls the algorithm used:
Downgrade attacks, confusion attack
Base64({ "alg": "HS256",
"typ": "JWS"})
…
. . …
32. By design: Confusion attack
PentesterLab.com / @PentesterLab
Exploitation:
• Get a token signed with RSA (you only have
access to the public key)
• Decode the header and change the algorithm
from RSA “RS256” to HMAC “HS256”
• Tamper with the payload
• Sign the token with the public RSA key
• Profit
33. By design: verifying signature
PentesterLab.com / @PentesterLab
…
Claims are optionals and not always supported*:
Always-valid tokens?
Base64({"user":"admin",
"exp":12…, "iat":1234.. }). . …
* Check https://jwt.io/
34. By design: verifying signature
PentesterLab.com / @PentesterLab
Claims are optionals
and not always
supported*
Always-valid tokens?
* Check https://jwt.io/
35. By design: verifying signature
PentesterLab.com / @PentesterLab
Signed data: you cannot (easily) manage quick-
revocation*:
The claim “jti” and a cache can be used to limit
the impact of this
No quick-revocation! Replay
* Unless you rotate the key or manage a server-side cache
36. By design: The None algorithm
PentesterLab.com / @PentesterLab
JWT RFC contains a None algorithm
No integrity!
Basically an unsigned token…
37. By design: The None algorithm
PentesterLab.com / @PentesterLab
Exploitation:
• Get a token
• Decode the header and change the algorithm to
“None” or “none”
• Decode and tamper with the payload
• Keep or remove the signature
• Profit
39. Libraries: CVE-2018-0114
PentesterLab.com / @PentesterLab
JWS allows you to add a “jwk” attribute (JSON Web
Key) to the header to tell the receiver what key was
used to sign the token:
40. Libraries: CVE-2018-0114
PentesterLab.com / @PentesterLab
• Vulnerability in Cisco Node Jose
• Node-Jose uses the embedded “jwk” key to check
the signature
Integrity bypass!
41. Libraries: CVE-2018-0114 - Exploitation
PentesterLab.com / @PentesterLab
Exploitation:
• Get a token
• Decode and tamper with the payload
• Generate a RSA key
• Add “n" & “e” to the header and use
RS256
• Sign the token with your RSA key
43. Libraries: Go-JOSE version <= 1.0.5
PentesterLab.com / @PentesterLab
From: https://rwc.iacr.org/2017/Slides/nguyen.quan.pdf
The issue:
44. Libraries: Go-JOSE version <= 1.0.5
PentesterLab.com / @PentesterLab
From: https://rwc.iacr.org/2017/Slides/nguyen.quan.pdf
The issue:
Integrity of the protected bypass!
45. Libraries: Go-JOSE version <= 1.0.5
PentesterLab.com / @PentesterLab
If the application trusts the protected*:
* you cannot change the payload
46. Libraries: Go-JOSE version <= 1.0.5 - Exploitation
PentesterLab.com / @PentesterLab
Exploitation:
• Get a token (compact or full)
• Modify it to use the full format
• Add your malicious protected
• Profit
48. Using Libraries: weak secret
PentesterLab.com / @PentesterLab
Some developers use weak secrets.
Reminder: you only need one token to brute force
the secret (completely offline)
Integrity bypass!
49. Using Libraries: decode vs verify
PentesterLab.com / @PentesterLab
A lot of libraries have two functions/methods:
• decode <- don’t use this one
• verify
Integrity bypass!
50. Using Libraries: decode vs verify
PentesterLab.com / @PentesterLab
Exploitation:
• Get a token
• Decode and tamper with the header or payload
• Profit
51. Using Libraries: not using exp or iat
PentesterLab.com / @PentesterLab
In many libraries you need to opt-in to use “exp” or
“iat”
Always-valid tokens?
53. Recommendations
PentesterLab.com / @PentesterLab
✓ Use strong keys and secrets
✓ Review the libraries you pick (KISS library)
✓ Make sure you check the signature
✓ Make sure your tokens expire
✓ Enforce the algorithm
54. Conclusion
PentesterLab.com / @PentesterLab
• JWT are complex and kind of insecure by design
• JWT libraries introduce very interesting bugs
• Make sure you test for those if you pentest or do
bug bounties
55. Any questions?
FOR YOUR TIME
THANKS!
louis@pentesterlab.com / PentesterLab.com / @PentesterLab