Exploiting Image Header Vulnerabilities: How I Achieved Remote Code Execution (RCE)
A friend recently forwarded me a website — let’s call it REDACTED.com — to test out for any issues. They’d heard about a potential vulnerability, and curiosity got the better of me. The website itself seemed pretty standard, with basic features like profile updates, posts, and uploads. But where there’s an upload feature, there’s often an opportunity.
First Glance
I started by creating a new account on the site to get a feel for things. The registration process was straightforward — just the usual email, and password fields. Nothing fancy there.
After logging in, I was greeted with a fairly standard profile page. The first thing that caught my eye was the profile picture upload feature — a simple “Edit Profile” button staring right at me.
These upload features always pique my interest because they’re often the weakest link in a website’s security. Developers tend to focus on the visible functionality while sometimes overlooking the security implications. But the developers weren’t entirely careless here; when I tried uploading a plain PHP file, it was immediately rejected. My dreams of simply uploading shell.php were crushed — for a moment.
Digging Deeper
After playing around with the upload feature, I noticed something interesting: the backend only cared about the headers of the file. If it detected an image header like \x89PNG, it was happy to let the file through. Now, what if I combined that with a malicious payload?
The idea was simple: I’d create a file that looked like an image at first glance but contained my PHP code underneath.
Crafting the Payload
Using PowerShell, I created a hybrid file with a PNG header followed by PHP code. The command looked like this:
$binaryContent = [byte[]](0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A) # PNG header
$phpCode = "<?php echo 'Malicious code executed!'; ?>" # PHP payload
$binaryContent | Set-Content -Path "shell.php" -Encoding Byte
Add-Content -Path "shell.php" -Value $phpCode
This created a file named shell.php that started with a valid PNG header but contained malicious PHP code that would execute commands.
The Upload
Next, I went back to REDACTED.com, logged into my test account, and uploaded shell.php as my profile picture. The system happily accepted the file and stored it in the upload directory at:
https://REDACTED.com/assets/upload-image/{random-id}-shell.php
Now, here comes the fun part.
Executing the Payload
I accessed the uploaded file via its URL:
https://REDACTED.com/assets/upload-image/{random-id}-shell.php
YEAH! It worked. I could execute any command on the server. At this point, I was laughing at how easy it was. All because the backend only checked file headers and not the actual content.
Impact
This vulnerability allowed me to achieve Remote Code Execution (RCE) on the server. Some potential risks included:
- Accessing sensitive server data.
- Uploading and executing backdoors.
- Privilege escalation.
- Server takeover.
Fixing the Issue
I reported the vulnerability to the website admins through my friend, along with the following recommendations:
Validate File Content:
- Use mime_content_type() to validate the actual file type.
- Ensure the file’s extension matches its MIME type.
Block Execution in Upload Directories:
- Configure the server to prevent execution of scripts in the upload directory using .htaccess:
<FilesMatch "\.(php|pl|py|cgi|asp|aspx)$">
Order Deny,Allow
Deny from all
</FilesMatch>
Store Files Safely:
- Save uploaded files in non-web-accessible directories.
- Use random filenames with extensions stripped.
Set Proper Permissions:
- Ensure the upload directory is non-executable with permissions like “chmod 0644”.
Final Thoughts
This was an interesting find, and it’s always fun uncovering vulnerabilities. The admins acknowledged the report and promised a fix (and maybe a reward). Let’s see how that goes.
For now, the lesson here is simple: always validate your uploads!