김승현
[Dreamhack : Web] file-download-1 본문
문제
file download 취약점이 있어서 그걸 활용해서 flag.py를 다운받으라는 문제인 것 같다.
풀이
접속하면 메뉴엔 Home, Upload My Memo가 있고 Please upload your memo!가 출력되어 있다.
upload my memo에 가보자.
filename과 content를 우리 마음대로 작성할 수 있는 것 같다.
이렇게 작성해서 한번 업로드 해보자.
그러면 이렇게 업로드가 되고
입력한 내용이 저장되어 있다. 근데 주소창을 잘 보면 메뉴에 없던 read라는 path로 읽는 걸 볼 수 있다.
소스 코드를 한 번 확인 해보자.
<전체 코드>
#!/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)
코드 초반부
os, shutil, flask. flag가 import되어 있는데 shutil은 파일과 파일 모음에 대한 여러 가지 고수준 연산을 제공하는
라이브러리라고 한다.
app = FLASK(__name__)을 통해 플라스크 객체를 생성하고 UPLOAD_DIR 변수에 uploads라는 문자열을 저장했다.
@APP.route('/') == host3.dreamhack.games:[port]/
files에 UPLOAD_DIR 변수에 있는 파일들의 리스트를 저장했고
render_template를 통해 index.htlml을 반환해주었다.
os.listdir은 해당 디렉토리에 있는 파일들의 리스트를 구할 수 있게 해주는 거라고 한다.
@APP.route('/upload') == host3.dreamhack.games:[port]/upload
메소드가 POST라면,
filename 변수에 사이트에서 전달된 filmename을 저장
content 변수에 사이트에서 전달된 content를 utf-8로 인코딩해서 저장 (utf-8 : 유니코드를 위한 가변 길이 문자 인코딩)
그리고 만약 filename에서 ..이 포함되어 있다면
render_template 함수를 통해 upload_result.html을 보여주는데 이때 bad characters,,를 출력하는 걸 리턴
[UPLOAD_DIR변수]/[filename변수] 경로에 있는 걸 binary 형식으로 작성한다. 그리고 코드에서 f라는 명칭으로 사용함
모두 종료되면 upload.html을 render_template 함수를 이용해서 반환(upload.html이 화면에 보임)
@APP.route('/read') == host3.dreamhack.games/read
erroe 변수에 False저장, data 변수는 byte 타입으로 저장받을 예정
filename 변수에 사이트에서 전달된 name 저장
[UPLOAD_DIR변수]/[filename변수] 경로에 있는 걸 binary 형식으로 읽는다. 이걸 코드에서 f라고 지칭할 예정
이게 실패한다면(에러 중에서 IsADirectoryError, FileNotFoundError들로 인해) error를 True로 변경
render_template 함수를 통해 read.hml을 filename의 이름을 가지고
content엔 data변수에 있는 내용을 utf-8로 디코드하고 error엔 유무를 판단한 걸 반환해서 보여준다.
if __name__ 부분
코드가 실행될 때(사이트가 실행될 때) 실행되는 부분이고
UPLOAD_DIR 경로 안에 파일이 존재한다면
파일들을 모두 다 지운다.
그리고 UPLOAD_DIR이라는 디렉토리를 만든다고 한다.
여기까지 코드를 보면 크게 upload와 read가 있다.
이건 upload의 코드 중 일부인데 ..을 필터링해서 사용 못하게 하니까 우리는 read를 이용해야 한다.
이건 read나 upload 둘 다 있는 건데 UPLOAD_DIR/[우리가 업로드한 파일] 이런 식으로 저장되는 걸 알 수 있다.
그렇다면 우리가 업로드 했던 파일을 read하고
거기서 ../을 입력하면 UPLOAD_DIR에 우리는 위치할 수 있다. 바로 해보자.
현재 디렉토리 정리 상위 디렉토리 하위 파일 UPLOAD_DIR - first_memo - flag.py |
이건 처음에 내가 업로드했던 파일이다.
주소는 http://host3.dreamhack.games:15702/read?name=fisrt_memo
주소에서 first_memo를 지우고 ../flag.py를 해보자.
짠
'Web > Dreamhack : Web' 카테고리의 다른 글
[Dreamhack : Web] Carve party (0) | 2023.02.23 |
---|---|
[Dreamhack : Web] web-ssrf (0) | 2023.02.23 |
[Dreamhack : Web] image-storage (0) | 2023.02.23 |
[Dreamhack : Web] command-injection-1 (0) | 2023.02.22 |
[Dreamhack : Web] mango (0) | 2023.02.22 |