대기중
10 코인 [WEB] Lv.3 | log in

문제코드

import secrets
from flask import Flask, request, render_template
from flask_cors import CORS
import requests
import func as F

app = Flask(__name__)
CORS(app)
app.secret_key = secrets.token_hex(32)

try:
    FLAG = open("./flag.txt", "r", encoding="utf-8").read().strip()
except:
    FLAG = "[**FLAG**]"

accounts = {"test": "1234", "admin": FLAG}

logging.getLogger('flask_cors').level = logging.DEBUG
open("log.txt", "w", encoding="utf-8").close()

file_handler = logging.FileHandler("log.txt", encoding="utf-8")
file_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(levelname)s:%(name)s:%(message)s')
file_handler.setFormatter(formatter)

root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)
root_logger.addHandler(file_handler)

@app.route("/")
def home():
    return render_template("index.html")

@app.route("/login", methods=["GET"])
def login():
    username = request.args.get("username")
    password = request.args.get("password")

    if username in accounts and accounts[username] == password:
        logging.debug(f"\nuser={username}")
        return "로그인 성공!"
    else:
        return "로그인 실패"

@app.route("/logout", methods=["GET"])
def logout():
    user = F.get_login_user()
    if user:
        logging.debug(f"user={user} logged out")
        logging.debug("\nuser=None")
        return f"{user} 로그아웃 성공!"
    else:
        return "로그인 상태가 아닙니다."

@app.route("/whoami", methods=["GET"])
def whoami():
    user = F.get_login_user()
    return user if user else "로그인 안됨"

@app.route('/calc', methods=['GET'])
def calc_proxy():
    user = F.get_login_user()
    if user != 'admin':
        return 'Get admin account', 403
    
    text = request.args.get('text')
    allowed_chars = "0123456789+-*/"
    if not all(char in allowed_chars for char in text):
        return 'Do not cheat!!!', 503
    
    try:
        response = requests.get(
            url=f'http://php_app:5000/?{request.query_string.decode()}',
            timeout=10
        )
        
        return str(eval(response.text, {'__builtins__': {}}))
    except:
        return 'PHP 서버 연결 실패', 503

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000, threaded=True)

func.py

def get_login_user():
    try:
        with open("log.txt", "r", encoding="utf-8") as f:
            for line in reversed(f.readlines()):
                line = line.strip()
                if line.startswith("user="):
                    username = line[len("user="):].strip()
                    if username=="None":
                        return None
                    return username
    except FileNotFoundError:
        return None
    return None

제가 지금 알아낸걸로는 f-string쪽에서 \n을 통한 개행이 가능한단 것과 whoami나 logout calc가 log의 마지막 user로 로그가 찍혀 있는걸로 검증을 하는거까지는 알아냈습니다 그리고 clac 부분에서 text 파라미터만 검사를 하는 취약점까진 발견했습니다 그러나 로그인 부분에서 \n을 넣어서 개행을 통해서 로그 인젝션을 시도해봤으나 비교문에서 개행문자들까지 같이 비교가 되서 실패했습니다 이 풀이 방법이 맞나요? 그리고 비교문을 어떻게 우회해야 할까요?? 답보다는 힌트를 주셨으면 좋겠습니다

작성자 정보
더 깊이 있는 답변이 필요할 때
드림핵 팀과 멘토에게 직접 문의해 보세요!
답변 0