이 문제는.. 사실 뒤에서 풀이자 적은 것부터 갑자기 풀다가 롸업이 필요한 수준까지는 아니길래 두문제정도는 그냥 풀었는데

이건 ...롸업도 없고 어떻게 풀어야 할지 감이 안잡히다가 풀어내긴 했지만! 롸업을 써야할 필요성을 느껴서 쓴다..

저 문제 설명(역사 => history)이 이 문제를 푸는데에 큰 도움이 되는 힌트이다.

이 문제를 푸는 핵심부터 말하자면

/read의 허술한 경로 필터를 우회해서 directory traversal을 하고 "history"를 읽어 flag의 위치를 알아내는 것이다.

이 과정을 알아보자.

1. app.py 소스 코드 주요 부분 분석

@APP.route('/read')
def read_memo():
    error = False
    data = b''
    filename = request.args.get('name', '')
    f = filename.replace("//", "/")
    f = f.replace("../", "")
    f = f.replace("./", "")
    f = f.replace("\\\\\\\\", "\\\\")
    f = f.replace("\\\\", "")
    try:
        with open(f'{UPLOAD_DIR}/{f}', 'rb') as f:
            data = f.read()
    except (IsADirectoryError, FileNotFoundError):
        error = True
    return render_template('read.html',
                           filename=filename,
                           content=data.decode('utf-8'),
                           error=error)

=> 하지만 필터 순서/방식 때문에 우회가 가능하다

2. 필터 우회 아이디어

우리가 원하는 최종 목표는:

f == "../something"

으로 만들어서,

open(f'uploads/{f}') # == open('uploads/../something')

→ 상위 디렉토리 파일에 접근하는 것이다.

..\//something <= 이렇게 쓰면 우리가 목표하는 바대로 접근이 가능하다.(필터 순서와 방식 때문에)

url로는 백슬래시를 인코딩하여 아래와 같은 형태가 되고 이것이 이 문제의 핵심 취약점이다.