Xin chào ! Nếu đây là lần đầu tiên bạn đến với diễn đàn, xin vui lòng danh ra một phút bấm vào đây để đăng kí và tham gia thảo luận cùng VnPro.
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • 🔥khai thác path traversal trong flask – từ input đến file nhạy cảm

    Khi xây dựng một Web API bằng Python Flask, việc nhận dữ liệu từ client và xử lý dữ liệu đó ở phía server là thao tác rất quen thuộc.

    Nhưng một câu hỏi quan trọng thường bị bỏ qua:

    Server sẽ làm gì nếu input mà client gửi lên không phải là giá trị mà developer dự kiến?

    Trong lab này, chúng ta xây dựng một Flask API có chức năng đọc file từ tham số filename, sau đó theo dõi toàn bộ data flow từ HTTP request → Python application → filesystem để tìm ra lỗ hổng Path Traversal.

    Mục tiêu không chỉ là biết chuỗi ../, mà quan trọng hơn là hiểu vì sao một input từ HTTP request có thể tác động trực tiếp đến filesystem của server.
    1️⃣ DỰNG FLASK APPLICATION


    Trước tiên cài Flask:
    py -m pip install flask


    Tạo file app.py:
    from flask import Flask

    app = Flask(__name__)

    @app.route('/')
    def home():
    return "Home page"

    if __name__ == "__main__":
    app.run(host="127.0.0.1", port=5000)


    Chạy application:
    py app.py


    Truy cập:



    Nếu nhận được Home page, Flask application đã hoạt động.

    Ở bước này chưa có vấn đề bảo mật. Điểm đáng chú ý chỉ bắt đầu xuất hiện khi application cho phép client chỉ định file nào cần đọc.
    2️⃣ BIẾN HTTP INPUT THÀNH FILESYSTEM OPERATION


    Tạo API:
    from flask import Flask, request

    @app.route('/get_file', methods=['GET'])
    def get_file():
    filename = request.args['filename']
    return f"Content of the file {filename} is...\n\n{cat(filename)}"


    Hàm cat():
    def cat(filename):
    with open(filename) as file:
    data = file.read()
    return data


    Hãy nhìn vào data flow:
    HTTP Request

    request.args['filename']

    filename

    open(filename)

    Filesystem

    HTTP Response


    Vấn đề nằm chính ở đây.

    Giá trị filename không được tạo bởi server mà đến trực tiếp từ HTTP request của client. Sau đó giá trị này được truyền thẳng vào open().

    Nói cách khác, application đang cho client tham gia quyết định server sẽ mở file nào.
    3️⃣ KIỂM TRA VỚI FILE HỢP LỆ


    Tạo:
    welcome.txt
    passwords.txt


    Ví dụ welcome.txt:
    Hello student


    Và passwords.txt:
    username=cisco
    password=cisco


    Request bình thường:



    Application trả về nội dung của welcome.txt.

    Thoạt nhìn API hoạt động hoàn toàn bình thường.

    Nhưng hãy đặt một câu hỏi khác:

    Nếu client không gửi tên file mà developer mong muốn thì sao?
    4️⃣ PATH TRAVERSAL XUẤT HIỆN Ở ĐÂU?


    Di chuyển passwords.txt ra ngoài thư mục chứa app.py.

    Sau đó thử:



    Ký hiệu:
    ../


    đại diện cho thư mục cha.

    Vì application không kiểm tra đường dẫn trước khi gọi:
    open(filename)


    nên filesystem có thể xử lý:
    ../passwords.txt


    như một đường dẫn hợp lệ.

    Nếu request thành công và server trả về nội dung passwords.txt, chúng ta đã chứng minh được Path Traversal.

    Điểm quan trọng ở đây không phải đơn giản là "../ nguy hiểm".

    Vấn đề thực sự là:
    Untrusted input từ client đang được sử dụng trực tiếp để xác định đường dẫn trên filesystem.

    Đây là một cách nhìn rất quan trọng khi làm DevNet Security.

    Thay vì chỉ nhìn vào một đoạn code, hãy đặt câu hỏi:

    Dữ liệu bắt đầu từ đâu → đi qua những function nào → cuối cùng tác động đến tài nguyên nào?
    5️⃣ FIX: KIỂM SOÁT INPUT


    Một cách tiếp cận trong lab là kiểm tra format của filename trước khi đưa vào open().

    Ví dụ:
    import re

    def sanitize_string(filename):
    if re.search(r'^[\w\-\.]+$', filename):
    pass
    else:
    raise ValueError("Can not use special characters")


    Sau đó:
    def cat(filename):
    sanitize_string(filename)

    with open(filename) as file:
    data = file.read()

    return data


    Bây giờ thử lại:



    Input chứa ký tự không nằm trong pattern cho phép sẽ bị từ chối trước khi đi tới:
    open(filename)


    Data flow lúc này trở thành:
    HTTP Request

    filename

    Validation

    Valid? ─── No ──→ Reject

    Yes

    open()

    Filesystem


    Chúng ta đã thêm một lớp kiểm soát giữa input của clientfilesystem.
    6️⃣ NHƯNG REGEX CÓ PHẢI GIẢI PHÁP TỐT NHẤT?


    Đây là điểm đáng suy nghĩ sau khi hoàn thành lab.

    Việc blacklist hoặc giới hạn ký tự có thể giúp minh họa cách ngăn payload trong bài lab, nhưng trong một ứng dụng thực tế, chỉ dựa vào việc lọc ký tự không phải lúc nào cũng là thiết kế an toàn nhất.

    Một hướng tốt hơn là:

    Không cho client tự do quyết định filesystem path.

    Thay vào đó, application nên:
    • Chỉ cho phép truy cập một thư mục được xác định trước.
    • Kiểm tra đường dẫn sau khi chuẩn hóa.
    • Đảm bảo file cuối cùng vẫn nằm trong thư mục được phép.
    • Chỉ cho phép những file cần thiết thay vì mở tùy ý mọi path.

    Ví dụ về tư duy thiết kế:
    User Input

    Normalize Path

    Resolve Absolute Path

    Check Allowed Directory

    Allowed? ── No → Reject

    Yes

    Read File


    Đây mới là tư duy quan trọng khi chuyển từ lab sang application thực tế.
    🎯 KẾT LUẬN


    Một Flask API vài dòng code có thể trở thành bài học rất rõ về Application Security.

    Từ một request:
    /get_file?filename=...


    dữ liệu có thể đi qua:
    HTTP

    Flask

    request.args

    Python variable

    open()

    Filesystem


    Nếu developer không kiểm soát đúng điểm giao giữa untrusted inputsensitive resource, một chức năng tưởng như đơn giản là “đọc file” có thể trở thành điểm yếu bảo mật.

    Vì vậy, giá trị lớn nhất của lab này không nằm ở việc nhớ payload ../.

    Nó nằm ở một thói quen quan trọng của DevNet:

    Đừng chỉ hỏi “API này có chạy không?”

    Hãy hỏi:

    “Input từ client đang đi đâu, được xử lý như thế nào và cuối cùng có thể tác động đến tài nguyên nào trên hệ thống?”

    Đó chính là cách chuyển từ tư duy viết code cho chạy sang tư duy xây dựng application an toàn.
    Attached Files
Working...
X