[Dreamhack Web - Lv.1] pathtraversal

문제 정보

사용자의 정보를 조회하는 API 서버입니다.

Path Traversal 취약점을 이용해 /api/flag에 있는 플래그를 획득하세요!

풀이 힌트

1. 공격 백터 파악

2. Path traversal 공격

문제 풀이

더보기
더보기

문제 페이지에 들어가니 무슨 기능을 하는 페이지인지 모르겠다.
Home, About, Contact 메뉴를 클릭하니, 아무 반응이 없었다.

 

Get User Info을 클릭하니 위 사진과 같은 페이지로 이동하였다.

 

어떤 기능을 하는지 확인하기 위해서 View 버튼을 클릭하니 guest 계정의 정보가 나왔다.

 

코드를 확인해보니, userid에 넣은 값이 users에 있는 값으로 변경되어 서버에 넘어간다.
그래서 버튼을 누르면 잠깐 guest에서 0으로 변경되었는데, 값이 변경이 되어 그렇게 된 것으로 보인다.

일단 페이지를 살펴봤지만 Path traversal 공격에 사용할 공격 백터는 userid로 보인다.
어떻게 작동하는지를 모르겠지만, userid에 Path traversal 공격을 시도해보겠다.

 

burp suite를 사용하여 userid를 ../flag로 수정하여 서버에 보냈다.

 

그 결과 Flag값이 출력되었다.

코드 분석

더보기
더보기
from flask import Flask, request, render_template, abort
from functools import wraps
import requests
import os, json

users = {
    '0': {
        'userid': 'guest',
        'level': 1,
        'password': 'guest'
    },
    '1': {
        'userid': 'admin',
        'level': 9999,
        'password': 'admin'
    }
}

def internal_api(func):
    @wraps(func)
    def decorated_view(*args, **kwargs):
        if request.remote_addr == '127.0.0.1':
            return func(*args, **kwargs)
        else:
            abort(401)
    return decorated_view

app = Flask(__name__)
app.secret_key = os.urandom(32)
API_HOST = 'http://127.0.0.1:8000'

try:
    FLAG = open('./flag.txt', 'r').read() # Flag is here!!
except:
    FLAG = '[**FLAG**]'

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/get_info', methods=['GET', 'POST'])
def get_info():
    if request.method == 'GET':
        return render_template('get_info.html')
    elif request.method == 'POST':
        userid = request.form.get('userid', '')
        info = requests.get(f'{API_HOST}/api/user/{userid}').text
        return render_template('get_info.html', info=info)

@app.route('/api')
@internal_api
def api():
    return '/user/<uid>, /flag'

@app.route('/api/user/<uid>')
@internal_api
def get_flag(uid):
    try:
        info = users[uid]
    except:
        info = {}
    return json.dumps(info)

@app.route('/api/flag')
@internal_api
def flag():
    return FLAG

application = app # app.run(host='0.0.0.0', port=8000)
# Dockerfile
#     ENTRYPOINT ["uwsgi", "--socket", "0.0.0.0:8000", "--protocol=http", "--threads", "4", "--wsgi-file", "app.py"]

Flask로 만들어진 문제 페이지의 코드를 살펴보겠다.

 

users = {
    '0': {
        'userid': 'guest',
        'level': 1,
        'password': 'guest'
    },
    '1': {
        'userid': 'admin',
        'level': 9999,
        'password': 'admin'
    }
}

User의 정보를 Dict형 변수에 넣어줬다.

 

@app.route('/get_info', methods=['GET', 'POST'])
def get_info():
    if request.method == 'GET':
        return render_template('get_info.html')
    elif request.method == 'POST':
        userid = request.form.get('userid', '')
        info = requests.get(f'{API_HOST}/api/user/{userid}').text
        return render_template('get_info.html', info=info)

Get 메소드로 /get_info 에 접속하면 get_info.html 를 보여준다.
Post 메소드로 userid를 보내면, /api/user/에 userid를 넣어서 Get메소드로 요청한다.

 

def internal_api(func):
    @wraps(func)
    def decorated_view(*args, **kwargs):
        if request.remote_addr == '127.0.0.1':
            return func(*args, **kwargs)
        else:
            abort(401)
    return decorated_view

@app.route('/api/user/<uid>')
@internal_api
def get_flag(uid):
    try:
        info = users[uid]
    except:
        info = {}
    return json.dumps(info)

접속하는 자의 IP 주소가 127.0.0.1이 아니라면 internal_api에 의해서 HTTP Status를 401로 보낸다.
만약 127.0.0.1이라면 get_flag 함수 인자에 /get_info 에서 보낸 userid가 들어간다.

그 후 users 변수에 저장된 user의 정보를 info 변수에 넣고 json형식으로 반환한다. 만약 users 변수에 없는 값을 요청한다면 info 변수는 {}가 넣어지고, 빈 값인 json형식으로 반환된다.

 

info = requests.get(f'{API_HOST}/api/user/{userid}').text

우리는 /get_info에서 userid를 ../flag를 넣어서 /api/user/../flag/api/flag로 되어 /api/flag에 Get메소드로 요청을 한 것이다.

 

@app.route('/api/flag')
@internal_api
def flag():
    return FLAG

그 결과 /api/flag 에서 Flag를 반환 받아 get_info.html에 flag를 출력할 수 있었던 것이다.

'Wargame > Dreamhack' 카테고리의 다른 글

[Dreamhack Web - Lv 1] file-download-1  (0) 2021.10.25
[Dreamhack Web - Lv 1] xss-1  (0) 2021.10.23
[Dreamhack Web - Lv 1] welcome  (0) 2021.10.15
[Dreamhack Web - Lv 1] simple_sqli  (0) 2021.10.15
[Dreamhack Web - Lv 1] cookie  (0) 2021.10.14