CTF, War game

[Dreamhack] Beginner: file-download-1

mnzy๐ŸŒฑ 2022. 9. 19. 04:44

1. ๋ฌธ์ œ 

https://dreamhack.io/wargame/challenges/37

 

file-download-1

File Download ์ทจ์•ฝ์ ์ด ์กด์žฌํ•˜๋Š” ์›น ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. flag.py๋ฅผ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์œผ๋ฉด ํ”Œ๋ž˜๊ทธ๋ฅผ ํš๋“ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Reference Introduction of Webhacking

dreamhack.io

 

File Download ์ทจ์•ฝ์ ์ด ์กด์žฌํ•˜๋Š” ์›น ์„œ๋น„์Šค๋ผ๊ณ  ์ œ์‹œ๋˜์–ด ์žˆ๋‹ค.

 


2. ํ•ด๊ฒฐ ๊ณผ์ •

(1) ๋ฌธ์ œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ

(2) ์ฝ”๋“œ ํ™•์ธ

- app.py ํŒŒ์ผ ํ™•์ธ

#!/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)

 

 

 

 /upload

  • upload ํŽ˜์ด์ง€์—์„œ๋Š” post ๋ฅผ ํ†ตํ•ด file name๊ณผ context๋ฅผ ํฌํ•จํ•˜์—ฌ ๊ธ€์„ ์„œ๋ฒ„์— ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ด๋•Œ, ํŒŒ์ผ ๋ช…์— ..์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. (..์ด ์žˆ์„ ๊ฒฝ์šฐ, ์ƒ์œ„ ๊ฒฝ๋กœ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค)
@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: # filename์— '..'์ด ๋ฐœ๊ฒฌ๋˜์ง€ ์•Š์„ ๊ฒฝ์šฐ์—๋งŒ if๋ฌธ ํƒˆ์ถœ
        
            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')

 

 

 /read

  • name์„ ๋ฐ›์•„์™€ ์„œ๋ฒ„์—์„œ ํŒŒ์ผ์„ ์ฝ์–ด์˜ค๋Š” ํŽ˜์ด์ง€์ด๋‹ค.
  • ์›น ํŽ˜์ด์ง€์— ํŒŒ์ผ ๋‚ด์šฉ์„ ํ‘œ์‹œํ•  ๋•Œ, ์œ„์™€ ๋‹ค๋ฅด๊ฒŒ ๋‹ค์šด๋กœ๋“œ ๋˜๋Š” ํŒŒ์ผ์— ๋Œ€ํ•ด ์–ด๋– ํ•œ ๊ฒ€์‚ฌ๋„ ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ๊ณต๊ฒฉ์— ์ทจ์•ฝํ•˜๋‹ค.
@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)

 

 

(3) ํŽ˜์ด์ง€ ์ ‘์†

 

http://host3.dreamhack.games:13703/

 

Upload My Memo ์ ‘์†

  • ํŒŒ์ผ๋ช…๊ณผ ๋‚ด์šฉ์„ form์œผ๋กœ ์ž…๋ ฅ๋ฐ›๋Š” ํ™”๋ฉด์ด ๋ณด์ธ๋‹ค.

 

 

์•„๋ฌด๋‚ด์šฉ์ด๋‚˜ ์ž…๋ ฅํ•ด๋ณด๊ณ  uploadํ•ด๋ณธ๋‹ค. 

 

 

๋‚ด๊ฐ€ ์—…๋กœ๋“œํ•œ ํŒŒ์ผ์ด ๋ฆฌ์ŠคํŠธ๋กœ ๋ณด์ด๊ณ , ํด๋ฆญํ•˜๋ฉด ๋ฉ”๋ชจ ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

  •  http://host3.dreamhack.games:13703/read?name=first
  • ์œ„์˜ ์ฝ”๋“œ์—์„œ ๋ถ„์„ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ, ํŒŒ์ผ์„ ์ฝ์–ด์˜ฌ ๋•Œ(๋‹ค์šด๋กœ๋“œ ํ•  ๋•Œ) 

 

 

(3) ๊ฒฝ๋กœ ์šฐํšŒ

๋”ฐ๋ผ์„œ read ํŽ˜์ด์ง€๋ฅผ ์ด์šฉํ•˜์—ฌ  '../' ๋ฅผ ์ž…๋ ฅํ•ด์„œ ๊ฒฝ๋กœ ์šฐํšŒ๋ฅผ ์‹œ๋„ํ–ˆ๋‹ค.

  • http://host3.dreamhack.games:13703/read?name=../flag.py 


3. ๋Œ€์‘ ๋ฐฉ๋ฒ•

์œ„ ํŽ˜์ด์ง€์—์„œ ํ•ด๋‹น ์ทจ์•ฝ์ ์„ ๊ณต๊ฒฉํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฐ€์žฅ ํฐ ์ด์œ ๋Š” ์—…๋กœ๋“œ์™€ ๋‹ฌ๋ฆฌ ๋‹ค์šด๋กœ๋“œ ํŽ˜์ด์ง€์—์„œ๋Š” '..'์„ ํ•„ํ„ฐ๋งํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋”ฐ๋ผ์„œ ๋‹ค์šด๋กœ๋“œ ํŽ˜์ด์ง€์—์„œ ..์„ ํ•„ํ„ฐ๋ง ํ•˜์—ฌ ๊ฒฝ๋กœ ์šฐํšŒ ๊ณต๊ฒฉ์„ ๋ง‰์•„์•ผ ํ•œ๋‹ค.

๋˜ํ•œ, .. ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด ์šฐํšŒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋”์šฑ ์—„๊ฒฉํ•œ ํ•„ํ„ฐ๋ง์ด ์žˆ์–ด์•ผ ํ•  ๊ฒƒ์ด๋‹ค.