Wargame - 웹

Dreamack - Dream Gallery

김가윤 2023. 10. 23. 01:13

문제

 

소스

입력받은 URL로부터 데이터를 읽어와 저장하는 기능이다.

from flask import Flask, request, render_template, url_for, redirect
from urllib.request import urlopen
import base64, os

app = Flask(__name__)
app.secret_key = os.urandom(32)

mini_database = []


@app.route('/')
def index():
    return redirect(url_for('view'))


@app.route('/request')
def url_request():
    url = request.args.get('url', '').lower()
    title = request.args.get('title', '')
    if url == '' or url.startswith("file://") or "flag" in url or title == '':
        return render_template('request.html')

    try:
        data = urlopen(url).read()
        mini_database.append({title: base64.b64encode(data).decode('utf-8')})
        return redirect(url_for('view'))
    except:
        return render_template("request.html")


@app.route('/view')
def view():
    return render_template('view.html', img_list=mini_database)


@app.route('/upload', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST':
        f = request.files['file']
        title = request.form.get('title', '')
        if not f or title == '':
            return render_template('upload.html')

        en_data = base64.b64encode(f.read()).decode('utf-8')
        mini_database.append({title: en_data})
        return redirect(url_for('view'))
    else:
        return render_template('upload.html')


if __name__ == "__main__":
    img_list = [
        {'초록색 선글라스': "static/assetA#03.jpg"}, 
        {'분홍색 선글라스': "static/assetB#03.jpg"},
        {'보라색 선글라스': "static/assetC#03.jpg"}, 
        {'파란색 선글라스': "static/assetD#03.jpg"}
    ]
    for img in img_list:
        for k, v in img.items():
            data = open(v, 'rb').read()
            mini_database.append({k: base64.b64encode(data).decode('utf-8')})
    
    app.run(host="0.0.0.0", port=80, debug=False)

 

 

 

풀이

간단한 문제이다.

이미지 요청 기능을 이용해서 저장되어 있는 flag.txt을 요청하면 된다.

 

URL에 http://www.example.com와 Ttitle에 Test 입력

 

이렇게 /view 페이지에 이미지가 생성된다.

 

개발자 도구로 살펴보니 base64로 데이터를 인코딩한다.

 

이미지 요청 기능인 /request 부분을 살펴보니 file uri 사용과 flag 문자열에 대해 필터링한다.

file uri를 사용해 로컬 컴퓨터에서 flag.txt에 접근하는 것을 필터링한다.

file://와 flag에 대한 필터링을 우회할 방법이 필요하다.

@app.route('/request')
def url_request():
    url = request.args.get('url', '').lower()
    title = request.args.get('title', '')
    if url == '' or url.startswith("file://") or "flag" in url or title == '':
        return render_template('request.html')

    try:
        data = urlopen(url).read()
        mini_database.append({title: base64.b64encode(data).decode('utf-8')})
        return redirect(url_for('view'))
    except:
        return render_template("request.html")

 

File URI Scheme란 로컬 컴퓨터에서 파일을 찾기 위해 사용된다.

"file://host/path" 포맷을 가지며 host는 시스템의 fully qualified domain name이며 여기서 path에 접근이 가능하다.

host부분은 생략이 가능하다. 만약 생략한다면 해당 URL이 수행되는 컴퓨터인 "localhost"로 자동 지정된다.

하지만 host부분이 생략된다고 해서 /도 생략되는 것이 아니기 때문에 "file:///path이 유용한 문법이다.

 

url.startswith("file://")는 단순히 앞에 공백을 넣어서 우회가 가능했고

flag문자열은 urlopen 함수가 url요청을 보내는 과정에서 디코딩을 수행하는 점을 이용해서 double encoding을 이용해 우회가 가능하다.

 

개발자 도구로 해당 이미지 부분을 살펴보면 base64로 인코딩된 데이터가 존재함을 알 수 있다.

 

base64로 디코딩하면 FLAG가 나온다.

import base64

data = "REh7YjIwMzdhMDI2YjQwY2M5ODgwNGU5MWI1YTJhMDdmNTR9"
code_bytes = data.encode('ascii')
decoded = base64.b64decode(code_bytes)
FLAG = decoded.decode('UTF-8')
print(FLAG)

'Wargame - 웹' 카테고리의 다른 글

Dreamhack - crawling  (0) 2023.10.20
Tomcat Manager  (0) 2023.10.18
filestorage  (0) 2023.06.03
[wargame.kr] fly me to the moon  (0) 2023.05.07
[wargame.kr] md5 password  (0) 2023.05.05