Exploiting JSON Web Tokens

JSON Web Tokens (JWT) are used primarily for authentication. When a user logs into a website successfully, the user is assigned a JWT in a cookie. These tokens offer users security mechanisms such as encryption and a signature. Additionally, JWT's follow the pattern of Base64(Header).Base64(Data).Base64(Signature). When headers are unsigned, attackers can manipulate it by changing the algorithm that is used in the signature of the JWT. In order to sign a header, the header itself needs to verify the signature and in turn, the signature needs to verify the header.


"JWTs generally have three parts: a header, a payload, and a signature. The header identifies which algorithm is used to generate the signature, and looks something like this:

header = '{"alg":"HS256","typ":"JWT"}'
HS256 indicates that this token is signed using HMAC-SHA256.

The payload contains the claims that we wish to make:

payload = '{"loggedInAs":"admin","iat":1422779638}'
As suggested in the JWT spec, we include a timestamp called iat, short for "issued at".

The signature is calculated by base64url encoding the header and payload and concatenating them with a period as a separator:

key = 'secretkey'
unsignedToken = encodeBase64(header) + '.' + encodeBase64(payload)
signature = HMAC-SHA256(key, unsignedToken)
To put it all together, we base64url encode the signature, and join together the three parts using periods:

token = encodeBase64(header) + '.' + encodeBase64(payload) + '.' + encodeBase64(signature)

# token is now:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYXQiOjE0MjI3Nzk2Mzh" (McLean, 2015).

There are a handful of signature methods that can be utilized to ensure the integrity of the JSON web tokens. These include:

  • RSA based
  • Elliptic curves
  • HMAC
  • None

More from Tim McLean:

“The none algorithm is a curious addition to JWT. It is intended to be used for situations where the integrity of the token has already been verified. Interestingly enough, it is one of only two algorithms that are mandatory to implement (the other being HS256).

Unfortunately, some libraries treated tokens signed with the none algorithm as a valid token with a verified signature. The result? Anyone can create their own "signed" tokens with whatever payload they want, allowing arbitrary account access on some systems.

Putting together such a token is easy. Modify the above example header to contain "alg": "none" instead of HS256. Make any desired changes to the payload. Use an empty signature (i.e. signature = "").

Most (hopefully all?) implementations now have a basic check to prevent this attack: if a secret key was provided, then token verification will fail for tokens using the none algorithm. This is a good idea, but it doesn't solve the underlying problem: attackers control the choice of algorithm.”

To exploit this vulnerability, I will use a lab from PentesterLab (http://pentesterlab.com) that provided a vulnerable web application. Additionally, I used Kali Linux (see version below), and Burp Suite. The steps followed for this exploit are below. Lastly, the FoxyProxy Mozilla Firefox web extension was used to route all traffic through the Burp Suite proxy (https://addons.mozilla.org/en-US/firefox/addon/foxyproxy-standard/)


Step One: Register as a new user



Step 2: Configure Burp Suite and FoxyProxy to listen on port 8181



Step 3: Refresh the browser to collect all of the HTTP traffic. Once collected, send the JSON web token to the repeater. (For this exercise, it is not necessary to have the interceptor enabled).



Step 4: Send the request and confirm you are logged in

Add caption

Step 5: Send the JWT to the decoder



Step 7: Decode the header to Base64


Step 8: Decode the data to Base64. Add an = sign at the end of the data and decode as Base64. As you can see, I am currently logged in as “testing”


Step 9: Change the algorithm from “HS256” to “None” and the login from “testing” to admin.


Step 10: Highlight the header and encode as Base64.



Step 11: Highlight the data and encode as Base64.


Step 12: Delete the signature portion of the re-encoded payload. Leave the trailing decimal point.


Step 13: Copy the new payload and replace the JWT in the repeater with the new one


Step 13: Click Go

Comments

Popular posts from this blog

Master Port List

Reflected Cross Site Scripting (XSS) Attacks

Installing and Configuring WebGoat