Secure Server
Secure Server
Platform: HackTheBox | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: D3v0o0Nu11 | Date: 2026-02-02 | Status: Solved Techniques: basename_sanitization, input_validation, lfi_to_rce, log_poisoning
Summary
Task: Fix vulnerabilities in a PHP web application that was exploited via LFI + log poisoning. Solution: Replace include with readfile, add basename() and regex validation to prevent path traversal.
Recon
Port scan
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
hackthebox| ID:20260202_hackthebox_secure_server - Tags: rce, lfi, path_traversal, php, log_poisoning, secure_coding
- Indicators: include with user input, no path validation, nginx access.log, User-Agent injection
- Source:
20260202_hackthebox_secure_server.md
Foothold
Vulnerability / Misconfiguration
- Basename_sanitization
- Input_validation
- Lfi_to_rce
- Log_poisoning
<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
- basename_sanitization
- input_validation
- lfi_to_rce
- log_poisoning
- Tags: rce, lfi, path_traversal, php, log_poisoning, secure_coding
Original Writeup
<details><summary>Click to expand original content</summary>Secure Server — HackTheBox
Description
Bobby made a secure server, but someone got in! How did they get in? Can you stop it from happening again?
This is a "secure coding" challenge where you need to identify and fix vulnerabilities in a PHP web application. The challenge provides:
- Access to the web application source code via SMB share
- An exploit script (exploit.py) showing how the attack works
- A checker service to verify fixes
Analysis
Vulnerability 1: Local File Inclusion (LFI) + Log Poisoning → RCE
The vulnerable code in our-projects.php:
<?php
$project = "orion";
if (isset($_GET["project"])) {
$project = strtolower($_GET["project"]);
}
?>
...
<p><?php include "../projects/" . $project; ?></p>
Problems identified:
includeexecutes PHP code from included files- No validation on
projectparameter allows path traversal (../) - Attacker can include any file on the system
Vulnerability 2: Path Traversal
No validation on the project parameter allowed ../ sequences to escape the intended directory and access arbitrary files like /var/log/nginx/access.log.
Attack Chain (from exploit.py)
from requests import get
IP = '127.0.0.1'
payload = 'whoami'
php_payload = f"<?php system('{payload}') ?>"
headers = {
'User-Agent': php_payload
}
# Step 1: Poison the log with PHP code in User-Agent
get(f'http://{IP}/', headers=headers)
# Step 2: Include the poisoned log via LFI
r = get(f'http://{IP}/our-projects.php?project=../../../../var/log/nginx/access.log')
print(r.text)
Attack flow:
- Send request with PHP payload in User-Agent header
- Nginx logs the malicious User-Agent to access.log
- Use LFI to include access.log
- PHP executes the injected code → RCE
Solution
Fix 1: Replace include with readfile
Changed from include (which executes PHP code) to readfile (which only outputs file contents as text):
// Before (vulnerable):
<p><?php include "../projects/" . $project; ?></p>
// After (fixed):
<p><?php readfile("../projects/" . $project); ?></p>
Why this works: readfile() outputs file contents as raw text without parsing PHP tags, preventing code execution even if malicious content is included.
Fix 2: Input Validation with basename() and regex
Added strict validation to prevent path traversal:
<?php
// default to Orion
$project = "orion";
if (isset($_GET["project"])) {
// Get basename first to strip any path components
$requested = basename($_GET["project"]);
// Convert to lowercase
$requested = strtolower($requested);
// Only allow alphanumeric characters, hyphens and underscores
if (preg_match('/^[a-z0-9_-]+$/', $requested)) {
$project = $requested;
}
}
?>
Defense layers:
basename()- strips directory components (../../../../etc/passwd→passwd)strtolower()- normalizes inputpreg_match('/^[a-z0-9_-]+$/')- whitelist only safe characters
Fix 3: XSS Protection (bonus)
Added htmlspecialchars for output to prevent reflected XSS:
<h1><?php echo htmlspecialchars(ucfirst($project)); ?></h1>
Complete Fixed Code
<?php
// default to Orion
$project = "orion";
$allProjects = ["orion", "ares", "ceres"];
if (isset($_GET["project"])) {
// Get basename first to strip any path components
$requested = basename($_GET["project"]);
// Convert to lowercase
$requested = strtolower($requested);
// Only allow alphanumeric characters, hyphens and underscores
if (preg_match('/^[a-z0-9_-]+$/', $requested)) {
$project = $requested;
}
}
?>
<!-- ... HTML ... -->
<h1><?php echo htmlspecialchars(ucfirst($project)); ?></h1>
<p><?php readfile("../projects/" . $project); ?></p>
Defense (Best Practices)
- Never use
include/requirewith user input - usereadfile()orfile_get_contents()instead - Always validate and sanitize user input with allowlists (regex, basename)
- Defense in depth - multiple layers of validation
- Use
htmlspecialchars()for all output to prevent XSS
Tools
- Docker - for running the challenge environment
- smbclient - for accessing files via SMB share
- curl - for testing the exploit and fixes
- netcat - for interacting with the checker service
- Python3 - for automation (smb_edit.py)
Notes
The challenge required maintaining functionality (dynamic file reading) while removing the security vulnerabilities. Simply restricting to a whitelist of projects wasn't acceptable - the checker tested with random project names, so the fix needed to allow arbitrary (but safe) filenames.
</details>Auto-tracked: saved to WriteUps; run
/xesor-reviseto fold lessons into XESXor_Methodology.md.
signed by XESXOR