Understanding, bypass and securing of Json Web Tokens (JWT)
Json Web Tokens allow the secure exchange of tokens between several parties. The security of the exchange translates into the verification of the integrity and authenticity of the data. It is carried out using multiple algorithms.
A token consists of three parts :
- A header, used to describe the token.
- A payload, which represents the information embedded in the token.
- A digital signature.
Example :
Header : {"alg": "HS256", "typ": "JWT"}
Payload : {"name":"JulienFink", "iat":1533777438}
Signature : 4V7KzBemrVji_kCyzGO3lQMZlBuVxryF3YhmMIr4kWI
The signature is crafted using a secret - 'Azerty123' in our case.
The "header", "payload" and "signature" parts are then encoded using base64url.
The complete JWT is a concatenation of these three parts, separated by a point (exception for the 'none' algorithm, which only has 2 parts - header and payload).
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSnVsaWVuRmluayIsImlhdCI6MTUzMzc3NzQzOH0.KJFzGjs_75Q56mY9QXqpEKU-wE2o3ufF3ZxfIUaexwI
Useful links for an overall understanding :
https://fr.wikipedia.org/wiki/JSON_Web_Token
https://jwt.io/
https://www.base64url.com/
Let us assume you don't have an account on a website, you don't want to create one and you decide to log in as a guest.
A JWT is assigned to your newly created session:
eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJ1c2VybmFtZSI6Imd1ZXN0In0.
{"typ":"JWT","alg":"none"}.{"username":"guest"}.
What would happen if we decided to change the value of the username to 'admin' ? We would get a new valid JWT and thus get access to the admin section.
eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJ1c2VybmFtZSI6ImFkbWluIn0.
{"typ":"JWT","alg":"none"}.{"username":"admin"}.
+ To avoid this type of Pr0bL3m, do not use 'none' algorithm.
What if we decided to change the algorithm to 'none' in the header part in order to exploit the previous vulnerability ? Let us try on a Root Me challenge (https://www.root-me.org/fr/Challenges/Web-Serveur/JSON-Web-Token-JWT-Introduction).
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1ZXN0In0.OnuZnYMdetcg7AWGV6WURn8CFSfas6AQej4V9M13nsk
{"typ":"JWT","alg":"HS256"}.{"username":"guest"}.'a signature crafted using a secret unknown to us'
We can craft our own JWT using the 'none' algorithm :
eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJ1c2VybmFtZSI6ImFkbWluIn0.
{"typ":"JWT","alg":"none"}.{"username":"admin"}.
Works !
+ To avoid this type of Pr0bL3m, use a whitelist of allowed algorithms. ['HS256']
- ['none']
The HS256/HS512 algorithm uses a secret value to define the signature like so :
HMACSHA256/512(concatenation, 'my_very_secret_key')
If the secret key is weak enough, we can brute force it using several tools like 'jwtcrack'.
Let's take a closer look at this Json Web Token :
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.7cKjnSm7ilrnEGAiUEUaMMcr7I0_bfydc_ACt1Hk-9E
{"typ": "JWT", "alg": "HS256"}.{"role": "guest"}.'a signature crafted using a secret unknown to us'
If we try to forge a new JWT - i.e. replacing the value of role by 'admin' - without knowing the secret, we will get an invalid token.
Brute forcing the token becomes therefore an option to bypass the server filtering :
Brute.force.HS256.secret.mp4
The secret value 'universe' is cracked under a second ! Since the same secret is used for each and every user, we can now craft our own 'admin' token with the newly discovered secret.
+ To avoid this type of Pr0bL3m, use strong shared secrets.
-- Coming soon !