
#!/usr/bin/python3
from flask import Flask, request, render_template, make_response, redirect, url_for
app = Flask(__name__)
try:
FLAG = open('./flag.txt', 'r').read()
except:
FLAG = '[**FLAG**]'
users = {
'guest': 'guest',
'admin': FLAG
}
@app.route('/')
def index():
username = request.cookies.get('username', None)
if username:
return render_template('index.html', text=f'Hello {username}, {"flag is " + FLAG if username == "admin" else "you are not admin"}')
return render_template('index.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
elif request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
try:
pw = users[username]
except:
return '<script>alert("not found user");history.go(-1);</script>'
if pw == password:
resp = make_response(redirect(url_for('index')) )
resp.set_cookie('username', username)
return resp
return '<script>alert("wrong password");history.go(-1);</script>'
app.run(host='0.0.0.0', port=8000)

ctrl + shift + f
누르면 전체 파일에 대해 검색이 가능함
#!/usr/bin/env python3
import os
import shutil
from flask import Flask, request, render_template, redirect
from flag import FLAG
APP = Flask(__name__)
UPLOAD_DIR = 'uploads'
@APP.route('/')
def index():
files = os.listdir(UPLOAD_DIR)
return render_template('index.html', files=files)
@APP.route('/upload', methods=['GET', 'POST'])
def upload_memo():
if request.method == 'POST':
filename = request.form.get('filename')
content = request.form.get('content').encode('utf-8')
if filename.find('..') != -1:
return render_template('upload_result.html', data='bad characters,,')
with open(f'{UPLOAD_DIR}/{filename}', 'wb') as f:
f.write(content)
return redirect('/')
return render_template('upload.html')
@APP.route('/read')
def read_memo():
error = False
data = b''
filename = request.args.get('name', '')
try:
with open(f'{UPLOAD_DIR}/{filename}', '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)
if __name__ == '__main__':
if os.path.exists(UPLOAD_DIR):
shutil.rmtree(UPLOAD_DIR)
os.mkdir(UPLOAD_DIR)
APP.run(host='0.0.0.0', port=8000)
Flask 애플리케이션에서 발생할 수 있는 경로 탐색 공격(path traversal attack) 취약점을 해결하기 위해 몇 가지 보완 작업을 적용해야 합니다. 경로 탐색 공격은 공격자가 파일 이름에 ../와 같은 문자를 포함시켜 애플리케이션이 의도하지 않은 디렉토리에 접근하게 만듭니다. 이를 통해 민감한 정보에 접근하거나 파일을 수정할 수 있습니다.
파이썬의 os.listdir()
지정한 디렉터리 혹은 현재 작업 디렉터리의 모든 파일과 디렉터리 명을 반환

왜 ../flag.py는 저장이 안 되는데 url에 ../flag.py라고 직접 입력하면 되는 거지?
ㄴ 이미 불러온 디렉터리 내에 flag.py가 존재하기 때문에
만약 gaza.py처럼 내가 등록한 것도 아니고 기존 디렉터리에 있는 파일이 아닌 이름을 입력하면

이렇게 된다
문제에서 flag.py를 다운받으라고 했으니 해당 파일은 이미 존재하는 것
근데 왜 ../를 써야하나
왜 ../를 쓰는지를 어떻게 알았냐
subprocess.CalledProcessError
가 뭐임?
왜냐면


flag.py를 직접 입력하니까 이렇게 되는데 코드를 보면
@APP.route('/ping', methods=['GET', 'POST'])
def ping():
if request.method == 'POST':
host = request.form.get('host')
cmd = f'ping -c 3 "{host}"'
try:
output = subprocess.check_output(['/bin/sh', '-c', cmd], timeout=5)
return render_template('ping_result.html', data=output.decode('utf-8'))
except subprocess.TimeoutExpired:
return render_template('ping_result.html', data='Timeout !')
except subprocess.CalledProcessError:
return render_template('ping_result.html', data=f'an error occurred while executing the command. -> {cmd}')
return render_template('ping.html')
except subprocess.CalledProcessError:
return render_template('ping_result.html', data=f'an error occurred while executing the command. -> {cmd}')
가 실행된 걸 알 수 있음