Ignition 1.3 'page.php' Local File Inclusion Explained

Ignition 1.3 'page.php' Local File Inclusion Explained
What this paper is
This paper details a Local File Inclusion (LFI) vulnerability in Ignition version 1.3, specifically within the page.php script. An attacker can exploit this to include and execute arbitrary files on the web server. The vulnerability was disclosed by cOndemned in December 2010.
Simple technical breakdown
The page.php script in Ignition 1.3 is designed to display content from HTML files located in the data/pages/ directory. It takes a page parameter from the URL, appends .html to it, and then checks if a file with that name exists. If it does, it includes the file's content.
The vulnerability lies in how the script handles the page parameter. It doesn't properly sanitize user input. This allows an attacker to provide a path that "escapes" the intended data/pages/ directory and points to other files on the server. By using directory traversal sequences (like ../) and a null byte (%00), an attacker can trick the script into including files outside of the expected directory, such as system configuration files or even other PHP scripts.
Complete code and payload walkthrough
Let's break down the provided page.php source code and the proof-of-concept (PoC) exploit.
<?php
1. session_start();
2. require "data/settings.php";
3. if (file_exists('data/pages/'.$_GET['page'].'.html')) {
4. include ('data/pages/'.$_GET['page'].'.html'); <----- LFI
5. }else{
6. die(
7. require('404.php')); }
?>Line 1:
session_start();- Purpose: Initializes or resumes a session. This is standard practice for web applications to maintain user state across requests.
- Input: None explicitly from the user in this context, but it uses session data if available.
- Behavior: Starts or continues a PHP session.
- Output: Sets up the
$_SESSIONsuperglobal array. - Practical Purpose: Session management, not directly related to the LFI vulnerability itself but part of the application's normal operation.
Line 2:
require "data/settings.php";- Purpose: Includes and evaluates the specified file. If the file is not found, it produces a fatal error and stops the script.
- Input: The hardcoded filename
"data/settings.php". - Behavior: Reads the content of
data/settings.phpand executes it as PHP code. This is likely where application-wide settings are defined. - Output: The settings defined in
data/settings.phpbecome available in the current script's scope. - Practical Purpose: Loads application configuration. This is a normal operation and not part of the exploit path.
Line 3:
if (file_exists('data/pages/'.$_GET['page'].'.html')) {- Purpose: Checks if a file exists. The filename is constructed by concatenating the string
'data/pages/', the value of the$_GET['page']parameter, and the string'.html'. - Input: The value of the
pageparameter from the URL's query string (e.g.,?page=somevalue). - Behavior: PHP's
file_exists()function checks for the presence of a file at the constructed path. - Output: Returns
TRUEif the file exists,FALSEotherwise. - Practical Purpose: This is the critical part where user input influences file path construction. The vulnerability occurs because
$_GET['page']is not properly validated or sanitized before being used in this path.
- Purpose: Checks if a file exists. The filename is constructed by concatenating the string
Line 4:
include ('data/pages/'.$_GET['page'].'.html'); <----- LFI- Purpose: Includes and evaluates the specified file. If the file is not found, it produces a warning but the script continues. This is the core of the LFI vulnerability.
- Input: The same constructed path as in
file_exists(), based on$_GET['page']. - Behavior: If the
file_exists()check passes (meaning the constructed path points to a file), this line attempts to include and execute that file. The attacker manipulates$_GET['page']to point to files outside the intendeddata/pages/directory. - Output: The content of the included file is displayed or executed.
- Practical Purpose: This is the vulnerability. By controlling
$_GET['page'], an attacker can force theincludestatement to load and execute arbitrary files.
Lines 5-7:
}else{ die( require('404.php')); }- Purpose: If the
file_exists()check on line 3 returnsFALSE, this block is executed. It terminates the script and displays a "404 Not Found" page. - Input: None from the user directly.
- Behavior: The
die()function stops script execution.require('404.php')attempts to include the404.phpfile. - Output: The content of
404.phpis displayed, and the script terminates. - Practical Purpose: Standard error handling. This block is bypassed when the LFI is successful because the
file_exists()check will pass for the attacker-controlled path.
- Purpose: If the
Proof of Concept (PoC) Breakdown:
http://[attacked_box]/[ignition1.3]/page.php?page=../../../../../etc/passwd%00
http://[attacked_box]/[ignition1.3]/page.php: This is the target URL, pointing to the vulnerable script.?page=: This indicates the start of the query string, and thepageparameter is being passed.../../../../../: This is the directory traversal sequence. It tells the script to move up three directories from the current location (data/pages/) multiple times. The exact number of../needed depends on the depth of thepage.phpscript within the web server's document root. The example uses five, suggesting a deep directory structure.etc/passwd: This is the target file the attacker wants to include. It's a standard Linux/Unix file containing user account information.%00: This is the URL-encoded representation of the null byte character (\0). In older PHP versions (before 5.3.0), the null byte could terminate string operations. When the script constructs the path like'data/pages/../../../../../etc/passwd.html', the null byte would effectively truncate the string before.htmlis appended, resulting in the pathdata/pages/../../../../../etc/passwd. This allows theincludefunction to access/etc/passwddirectly, bypassing the.htmlextension check.
Note on magic_quotes_gpc: The paper mentions that magic_quotes_gpc should be turned off. This is because magic_quotes_gpc automatically escapes single quotes, double quotes, and backslashes. If it were enabled, it could interfere with the null byte termination or other characters used in exploit payloads.
Mapping list:
session_start();-> Application state management (not exploitable here).require "data/settings.php";-> Application configuration loading (not exploitable here).file_exists('data/pages/'.$_GET['page'].'.html')-> Vulnerable path construction point. User input directly influences the file path being checked.include ('data/pages/'.$_GET['page'].'.html')-> Vulnerable file inclusion point. Executes code or displays content from the attacker-controlled path.../../../../../-> Directory traversal payload.etc/passwd-> Target file payload.%00-> Null byte payload (for string termination in older PHP).
Practical details for offensive operations teams
- Required Access Level: Low-privileged access to the web application is sufficient. The vulnerability is client-side exploitable via HTTP requests.
- Lab Preconditions:
- A web server running a vulnerable version of Ignition (1.3).
- PHP configured with
magic_quotes_gpcdisabled. This is a critical prerequisite. Ifmagic_quotes_gpcis enabled, the null byte termination might not work as expected, and other sanitization might occur. - The web server must have read permissions for the target file (e.g.,
/etc/passwd). - The web application must be accessible over HTTP/HTTPS.
- Tooling Assumptions:
- A web browser for manual testing or a web proxy like Burp Suite or OWASP ZAP for intercepting and modifying requests.
- A command-line interface for interacting with the target system if shellcode execution is attempted.
- Tools to identify the web server's directory structure and PHP configuration.
- Execution Pitfalls:
magic_quotes_gpcenabled: As mentioned, this is the primary blocker. If it's on, the null byte might be escaped, preventing the intended string termination.- File permissions: The web server process must have read permissions for the target file. For example, a web server running as
www-datamight not be able to read/etc/shadow. - Path traversal depth: The number of
../sequences needs to be correct for the application's directory structure. Too few won't escape the directory; too many might go too high and fail. - File extension bypass: The
.htmlextension is appended. The null byte (%00) is crucial for truncating the string before this extension is added. If the null byte doesn't work (e.g., due to PHP version or configuration), alternative bypasses might be needed, though they are less likely to be effective with this specific code. - Web Application Firewalls (WAFs): Modern WAFs are likely to detect and block common LFI payloads like
../../etc/passwd. - File existence check: The
file_exists()check must pass. If the target file doesn't exist at the constructed path, theincludewill not be reached.
- Tradecraft Considerations:
- Reconnaissance: Understand the target application's directory structure. Identify the root of the web application.
- Parameter Discovery: Confirm that
page.phpis accessible and that thepageparameter is indeed used. - Payload Crafting: Experiment with different traversal depths (
../) and target files. - Null Byte Effectiveness: Test if
%00works. If not, research alternative methods for string termination or bypasses specific to the PHP version. - Information Gathering: The primary goal is often to read sensitive files like configuration files (e.g.,
config.php,database.php) to extract credentials or other secrets. Reading/etc/passwdis a common initial step to enumerate users. - Remote Code Execution (RCE): If the attacker can include a PHP file that they have uploaded to the server (e.g., via a file upload vulnerability), they can achieve RCE. This requires a separate vulnerability or a way to place a malicious file. The LFI itself doesn't directly provide RCE unless the server allows including arbitrary files that are already executable or contain malicious PHP code.
Where this was used and when
- Context: This vulnerability was found in Ignition, a PHP web application framework/CMS. It would be present on any server running Ignition version 1.3.
- Timeframe: Disclosed in December 2010. Exploitation would have been relevant from that point until Ignition versions were patched or updated. Given the age, it's unlikely to be a widespread active threat against modern, maintained systems, but it serves as a classic example of LFI.
Defensive lessons for modern teams
- Input Validation and Sanitization: Never trust user input. Always validate and sanitize all external input, especially data used in file paths, database queries, or system commands.
- Principle of Least Privilege: Ensure that web server processes have only the necessary read permissions for files. Avoid granting broad read access to sensitive system files.
- Secure File Handling: When including files based on user input, use whitelisting of allowed files or directories rather than blacklisting or relying on path traversal prevention alone.
- PHP Configuration: Keep PHP updated. Newer versions have removed or mitigated the impact of older vulnerabilities like the null byte termination issue. Ensure
magic_quotes_gpcis disabled (as it's deprecated and removed in later PHP versions) but understand its historical implications. - Web Application Firewalls (WAFs): Deploy and configure WAFs to detect and block common LFI patterns. However, WAFs are not a silver bullet and should be part of a layered security approach.
- Code Auditing: Regularly audit web application code for common vulnerabilities like LFI, SQL injection, XSS, etc.
ASCII visual (if applicable)
This vulnerability is primarily a code-level issue within a single script, so a complex architecture diagram isn't strictly necessary. However, we can visualize the flow of data and control:
+-----------------+ +-----------------+ +-----------------+
| Attacker (User) |----->| Web Browser/ |----->| Web Server |
| | | Proxy | | (Ignition 1.3) |
+-----------------+ +-----------------+ +-----------------+
|
| HTTP Request
| (e.g., ?page=...)
v
+-------------+
| page.php |
+-------------+
|
| 1. $_GET['page']
v
+-------------+
| Path Build |
| (data/pages/|
| <input>.html)|
+-------------+
|
| 2. file_exists()
v
+-------------+
| Check File |
| Existence |
+-------------+
|
| 3. If EXISTS: include()
v
+-------------+
| Include/ |
| Execute |
| Target File |
+-------------+
|
| 4. Output
v
+-----------------+
| Response to |
| Attacker |
+-----------------+Explanation of the diagram:
- The attacker sends an HTTP request with a crafted
pageparameter. - The
page.phpscript receives this parameter and constructs a file path. file_exists()checks if the constructed path points to a real file.- If the file exists (due to successful path traversal),
include()is called, fetching and executing/displaying the content of the target file. - The output from the included file is sent back to the attacker.
Source references
- Paper ID: 15864
- Paper Title: Ignition 1.3 - 'page.php' Local File Inclusion
- Author: cOndemned
- Published: 2010-12-30
- Paper URL: https://www.exploit-db.com/papers/15864
- Download URL (mentioned in paper):
http://launchpad.net/ignition/trunk/1.3/+download/ignition-1.3.tar.gz
Original Exploit-DB Content (Verbatim)
Ignition 1.3 (page) Local File Inclusion Vulnerability
disclosed by cOndemned
download:
http://launchpad.net/ignition/trunk/1.3/+download/ignition-1.3.tar.gz
note:
1. Magic_quotes_gpc should be turned off in order to exploit this vulnerability
2. LFI bugs found by me in previous version (1.2) are still working in this one
source of page.php
1. <?php
2. session_start();
3. require "data/settings.php";
4. if (file_exists('data/pages/'.$_GET['page'].'.html')) {
5. include ('data/pages/'.$_GET['page'].'.html'); <----- LFI
6. }else{
7. die(
8. require('404.php')); }
proof of concept:
http://[attacked_box]/[ignition1.3]/page.php?page=../../../../../etc/passwd%00
http://[attacked_box]/[ignition1.3]/page.php?page=../../../../../[localfile]%00