How We Audited a High-Traffic Magento 2 Enterprise Stack on AWS and Mitigated Remote Code Execution (RCE) via insecure file uploads
Initial Triage: Identifying the Attack Vector
Our engagement began with a critical alert: a high-traffic Magento 2 Enterprise stack hosted on AWS was exhibiting anomalous behavior, hinting at a potential compromise. The initial forensic analysis pointed towards an insecure file upload vulnerability. Specifically, logs indicated that a non-image file, disguised with a seemingly innocuous MIME type, had been successfully uploaded to a web-accessible directory. This file, upon execution, would grant an attacker remote code execution (RCE) capabilities on the server.
The core of the vulnerability lay in Magento’s handling of user-submitted files, particularly within custom modules or themes that might bypass core validation mechanisms. In this instance, a third-party extension, intended for media asset management, had a critical flaw: it failed to adequately validate file types and content, relying instead on a weak check of the `Content-Type` header and a simple file extension filter.
Deep Dive: Analyzing the Exploited Module
We focused our investigation on the `app/code/Vendor/Module/Controller/Adminhtml/Upload.php` file, which was identified as the entry point for the malicious upload. The relevant snippet of code, simplified for clarity, looked something like this:
// Simplified representation of the vulnerable code
public function execute() {
$uploader = $this->_fileUploaderFactory->create(
'file' // Field name from the form
);
$uploader->setAllowedExtensions(['jpg', 'jpeg', 'gif', 'png']); // Weak extension check
$uploader->setFilesDispersion(true);
$uploader->setAllowRenameFiles(true);
$result = $uploader->save($this->_fileSystem->getDirectoryWrite(
DirectoryList::MEDIA
)->getAbsolutePath('uploads/user_files')); // Uploads to a web-accessible path
if ($result['file']) {
// Further processing, potentially insecurely
// ...
}
// ...
}
The primary weakness here is the `setAllowedExtensions` method. While it attempts to restrict file types, it’s easily bypassed by simply renaming a malicious script (e.g., `shell.php`) to something like `shell.jpg`. The `Content-Type` header is also notoriously unreliable, as it can be easily spoofed by the client. The `save()` method then writes the file to a directory that, in this specific Magento configuration, was served directly by Nginx without further content type validation or execution prevention.
Reconnaissance and Exploitation Simulation
To confirm the exploitability, we simulated the attack in a controlled staging environment. The attacker’s goal would be to upload a PHP webshell. A common payload for this is a simple script that allows arbitrary command execution.
Step 1: Crafting the Webshell
<?php
// webshell.php
if(isset($_REQUEST['cmd'])){
echo "<pre>";
$cmd = ($_REQUEST['cmd']);
system($cmd);
echo "</pre>";
die;
}
?>
Step 2: Bypassing the Extension Filter
The attacker would rename `webshell.php` to `webshell.jpg` and upload it. The `Content-Type` header could be set to `image/jpeg` or even `application/octet-stream` to further obfuscate the upload.
Step 3: Executing Commands
Once uploaded to a web-accessible path (e.g., `/pub/media/uploads/user_files/webshell.jpg`), the attacker could then access it via a URL like `https://your-magento-site.com/pub/media/uploads/user_files/webshell.jpg?cmd=ls -la` to execute commands.
AWS Infrastructure and Configuration Review
Our audit extended to the AWS infrastructure. The Magento stack was deployed across several EC2 instances behind an Application Load Balancer (ALB). Key components included:
- EC2 Instances: Running Amazon Linux 2 with Nginx as the web server.
- RDS Instance: For the Magento database.
- S3 Bucket: Potentially for static assets or backups, though not directly involved in this RCE.
- Security Groups: Configured to allow traffic on ports 80 and 443.
- IAM Roles: Assigned to EC2 instances for AWS service access.
The critical observation was that the Nginx configuration for serving media files was too permissive. The `uploads/user_files` directory was configured to serve static content directly, without any server-side validation or execution prevention. A typical Nginx configuration snippet that would allow this vulnerability to be exploited looks like this:
server {
listen 80;
server_name your-magento-site.com;
root /var/www/magento2/public_html;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ ^/pub/ {
alias /var/www/magento2/public_html/pub/;
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; # Example PHP-FPM socket
}
}
# Vulnerable location for uploads
location /pub/media/uploads/user_files/ {
autoindex on; # Often enabled for debugging, but a risk
# No specific directives to prevent script execution
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; # Example PHP-FPM socket
}
}
The lack of a specific `location` block to deny execution of PHP files within the `/pub/media/uploads/user_files/` directory, or a `try_files` directive that would prevent direct access to executable scripts, was the server-side enabler of the exploit.
Mitigation Strategy: A Multi-Layered Approach
Addressing this RCE required a comprehensive strategy, focusing on both immediate containment and long-term hardening.
1. Immediate Containment: Isolating and Cleaning
The first step was to prevent further exploitation and remove the malicious payload. This involved:
- Temporarily Disabling Upload Functionality: If possible, disabling the specific module or feature responsible for file uploads.
- Identifying and Removing Malicious Files: Scanning the `uploads/user_files` directory and any other suspicious locations for webshells or unexpected files. This often requires manual inspection and pattern matching.
- Reviewing Server Logs: Analyzing Nginx access and error logs, as well as PHP-FPM logs, for any signs of command execution or unusual activity.
- Isolating Affected Instances: If a compromise was confirmed, isolating the affected EC2 instance from the network (except for necessary diagnostic access) to prevent lateral movement.
2. Code-Level Fixes: Securing the Upload Module
The most critical fix was to secure the vulnerable third-party module. This involved:
Enhanced File Validation:
// Inside app/code/Vendor/Module/Controller/Adminhtml/Upload.php
// ...
$uploader = $this->_fileUploaderFactory->create('file');
// 1. Strict MIME type validation using Magento's File Uploader
$allowedMimeTypes = [
'image/jpeg',
'image/png',
'image/gif',
];
$fileInfo = $uploader->getFileInfo();
if (!in_array($fileInfo['type'], $allowedMimeTypes)) {
throw new \Magento\Framework\Exception\LocalizedException(__('Invalid file type.'));
}
// 2. Content validation (e.g., using finfo or a library)
// This is more complex and might involve checking file headers or using a dedicated library.
// For simplicity, we'll focus on stricter extension and MIME checks here.
// 3. Whitelisting allowed extensions (as a secondary check)
$uploader->setAllowedExtensions(['jpg', 'jpeg', 'png']); // Still useful as a fallback
// ... rest of the save logic
Restricting Upload Directories: Ensuring that uploaded files are *never* placed in a web-accessible directory that is also configured to execute PHP scripts. Ideally, uploads should go to a non-web-accessible location, and files should be served via a controlled script that performs necessary checks.
3. Server-Level Hardening: Nginx Configuration
The Nginx configuration was modified to prevent direct execution of scripts from upload directories:
server {
listen 80;
server_name your-magento-site.com;
root /var/www/magento2/public_html;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ ^/pub/ {
alias /var/www/magento2/public_html/pub/;
# Ensure PHP files are processed by PHP-FPM
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
}
# Secure the uploads directory
location /pub/media/uploads/user_files/ {
# Deny direct execution of PHP files
location ~ \.php$ {
return 403; # Forbidden
}
# Optionally, deny access to all executable files if not needed
# deny all;
# If files need to be served, do it via a controlled script
# For example, a PHP script that checks permissions and serves the file.
# try_files $uri =404; # This would serve static files but not execute scripts
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
}
The key change is the addition of a nested `location ~ \.php$` block within the `/pub/media/uploads/user_files/` configuration that returns a `403 Forbidden` status, effectively preventing any PHP script in that directory from being executed by the web server.
4. AWS Security Best Practices
Beyond the immediate fix, we recommended reinforcing AWS security posture:
- Web Application Firewall (WAF): Implementing AWS WAF with rules to detect and block common attack patterns, including those targeting file uploads.
- EC2 Instance Hardening: Regularly patching OS and software, disabling unnecessary services, and implementing intrusion detection systems (IDS).
- IAM Least Privilege: Ensuring EC2 instances and users have only the minimum necessary permissions.
- VPC Network Segmentation: Using security groups and network ACLs to restrict traffic flow between different tiers of the application (e.g., web servers, database servers).
- Regular Security Audits: Automating vulnerability scanning and penetration testing.
Post-Mitigation Verification and Monitoring
After implementing the code and configuration changes, a thorough verification process was conducted. This included:
- Re-testing the Exploit: Attempting to upload a malicious file again to confirm that the vulnerability is indeed patched.
- Log Analysis: Continuously monitoring Nginx, PHP-FPM, and AWS CloudTrail logs for any suspicious activity.
- Intrusion Detection System (IDS) Alerts: Ensuring that any IDS or security monitoring tools are configured to detect and alert on similar attack attempts.
- Performance Monitoring: Verifying that the security measures have not negatively impacted application performance.
This case study highlights the critical importance of robust input validation, secure file handling practices, and a defense-in-depth approach that combines application-level security with infrastructure hardening. For high-traffic, business-critical platforms like Magento Enterprise, neglecting these aspects can lead to severe security breaches with significant financial and reputational consequences.