Web Hacking/Dreamhack 풀이

Addition calculator

박연준 2023. 12. 24. 15:39

해당 문제는 Dreamhack CTF Season 4 Round #10 (🌱Div2) 에 출제된 문제입니다.

 

문제 설명

  • 덧셈 식을 입력하면 계산 결과를 출력하는 웹 서비스입니다. ./flag.txt 파일에 있는 플래그를 획득하세요.
  • 플래그 형식은 DH{...} 입니다.

 

풀이

 

app.py의 소스 코드는 다음과 같다.

#!/usr/bin/python3
from flask import Flask, request, render_template
import string
import subprocess
import re


app = Flask(__name__)


def filter(formula):
    w_list = list(string.ascii_lowercase + string.ascii_uppercase + string.digits)
    w_list.extend([" ", ".", "(", ")", "+"])

    if re.search("(system)|(curl)|(flag)|(subprocess)|(popen)", formula, re.I):
        return True
    for c in formula:
        if c not in w_list:
            return True


@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == "GET":
        return render_template("index.html")
    else:
        formula = request.form.get("formula", "")
        if formula != "":
            if filter(formula):
                return render_template("index.html", result="Filtered")
            else:
                try:
                    formula = eval(formula)
                    return render_template("index.html", result=formula)
                except subprocess.CalledProcessError:
                    return render_template("index.html", result="Error")
                except:
                    return render_template("index.html", result="Error")
        else:
            return render_template("index.html", result="Enter the value")


app.run(host="0.0.0.0", port=8000)

 

 

위의 소스 코드를 하나씩 분석해보면 아래와 같이 w_list 라는 변수에 알파벳 소문자와 대문자, 숫자를 넣고, 공백, . , (, ), +  기호를 추가하였다.

w_list = list(string.ascii_lowercase + string.ascii_uppercase + string.digits)
w_list.extend([" ", ".", "(", ")", "+"])

 

 

다음은 re.search라는 함수를 사용하여 formula 문자열 내에 특정 패턴이 있는지 검사한다. system, curl, flag, subprocess, popen 문자열 중 하나라도 formula 문자열 내에 포함되어 있다면 True를 반환하는 것을 알 수 있다. re.I는 대소문자를 구분하지 않는 검색을 의미한다.

if re.search("(system)|(curl)|(flag)|(subprocess)|(popen)", formula, re.I):
    return True

 

 

아래를 보면 formula의 각 문자인 c에 대해서 c가 w_list에 포함되어 있지 않으면 True를 반환한다. 조금 쉽게 얘기하면 formula에 w_list에 없는 어떤 문자라도 포함되어 있으면 True를 반환한다.

for c in formula:
    if c not in w_list:
        return True

 

 

아래 코드를 분석해보면 / 경로에 대해서 GET과 POST 메소드를 지원하고, GET 메소드는 기본 index.html을 보여준다. POST 메소드라면 formula에 입력된 값을 가져오고, 값이 없다면 빈 문자열을 기본값으로 사용한다. 만약 빈 문자열이 아니라면 앞서 정의한 filter 함수를 사용해서 필터링하고 True를 반환하면 Filtered라는 문자열이 표시된다. 또한 false를 반환하게 된다면 eval 함수를 사용해 result의 값에 formula의 값으로 그대로 출력해준다.

@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == "GET":
        return render_template("index.html")
    else:
        formula = request.form.get("formula", "")
        if formula != "":
            if filter(formula):
                return render_template("index.html", result="Filtered")
            else:
                try:
                    formula = eval(formula)
                    return render_template("index.html", result=formula)
                except subprocess.CalledProcessError:
                    return render_template("index.html", result="Error")
                except:
                    return render_template("index.html", result="Error")
        else:
            return render_template("index.html", result="Enter the value")

 

따라서 filter 함수에 맞게끔 system, curl, flag, subprocess, popen 키워드를 사용하지 않고 w_list의 리스트에 준수해서 ./flag.txt 의 값을 읽으면 된다. 일단 한 번 100 + 2를 입력해 잘 수행되는지 테스트 해보았다.

 

 

 

이제 flag는 ./flag.txt 에 위치하고 있다. 따라서 파이썬에서는 open이라는 함수를 사용하여 파일을 읽을 수 있는데 일반적인 방법으로 다음과 같이 사용한다.

with open('./flag.txt', 'r') as file:
    content = file.read()

 

 

따라서 open이라는 함수를 키워드하고 있지 않고, chr 함수 또한 아스키코드에 해당하는 문자를 반환해주기 때문에 적용하면 다음과 같다.

open(chr(46)+chr(47)+chr(102)+chr(108)+chr(97)+chr(103)+chr(46)+chr(116)+chr(120)+chr(116)).read()

 

위처럼 한 이유는 아래처럼 코드를 작성하면 flag가 키워드에 걸리기 때문에 위에 있는 chr 함수를 사용한 것이다.

open(.flag.txt).read()

 

 

따라서 입력하면 다음과 같이 flag를 확인할 수 있다.

'Web Hacking > Dreamhack 풀이' 카테고리의 다른 글

Relative Path Overwrite Advanced  (1) 2024.01.02
Relative Path Overwrite  (1) 2024.01.02
CSS Injection 풀이  (0) 2023.07.01
Client Side Template Injection 풀이  (0) 2023.06.26
CSRF Advanced  (0) 2023.06.26