Media Library Upload Abuse
How Media Library Normally Works
By default:
WordPress allows uploads only of safe file types:
Images (
.jpg,.jpeg,.png,.gif,.webp)Documents (
.pdf,.docx,.pptx)Archives (
.zip)Media (
.mp3,.mp4,.wav)
Uploads are stored in:
/wp-content/uploads/{year}/{month}/Apache web server configuration.
Itβs usually placed in
.htaccessfiles inside folders to prevent PHP execution.
<FilesMatch "\.php$">
deny from all
</FilesMatch>So under normal configs, even if you uploaded shell.php, it wonβt run, it will just sit there as a static file.
Basic Exploit Flow (Just for basic understading)
Attacker uploads malicious file:
shell.php.jpgcontaining:
Due to misconfigure, server parses it as PHP.
Attacker visits:
Boom β Remote Code Execution (RCE).
Basic bypass upload
Most versions validate files by checking the extension, magic bytes, or MIME type β but these checks can often be bypassed with a carefully crafted file.
Bypass file extensions checks:
All file types:
PHP: .php, .php2, .php3, .php4, .php5, .php6, .php7, .phps, .pht, .phtm, .phtml, .pgif, .shtml, .htaccess, .phar, .inc, .hphp, .ctp, .module
Working in PHPv8: .php, .php4, .php5, .phtml, .module, .inc, .hphp, .ctp
Uppercase letters
If they not worked, test them using some uppercase letters: pHp, .pHP5, .PhAr
Check adding a valid extension before the execution extension (use previous extensions also):
file.png.php
file.png.Php5
Try adding special characters at the end. You could use Burp to bruteforce all the ascii and Unicode characters. (Note that you can also try to use the previously motioned extensions)
file.php%20
file.php%0a
file.php%00
file.php%0d%0a
file.php/
file.php.\
file.
file.php....
file.pHp5....
Try to bypass the protections tricking the extension parser of the server-side with techniques like doubling the extension or adding junk data (null bytes) between extensions. You can also use the previous extensions to prepare a better payload.
file.png.php
file.png.pHp5
file.php#.png
file.php%00.png
file.php\x00.png
file.php%0a.png
file.php%0d%0a.png
file.phpJunk123png
Add another layer of extensions to the previous check:
file.png.jpg.php
file.php%00.png%00.jpg
Bypassing Magic Number Checks
Some applications inspect the file's Magic Number (the first few bytes of a file) to verify its actual type, regardless of the file extension. Attackers can bypass this by appending the correct Magic Number at the beginning of a malicious file.
How to bypass Magic Number checks:
Method 1: Prepending a valid Magic Number
You can insert the Magic Number of a valid image at the beginning of a malicious file to trick the server into accepting it as an image:
Explanation:
\x89\x50\x4E\x47\x0D\x0A\x1A\x0Aβ This is the Magic Number for a PNG file.cat shell.php >> fake.pngβ Appends a PHP shell to the image file.
Method 2: Embedding a backdoor inside metadata
Another approach is to hide a PHP shell inside the metadata of an image:
Explanation:
The PHP shell is stored in the imageβs metadata, making it harder to detect.
The
__halt_compiler();function stops PHP from interpreting the rest of the image file, ensuring only the backdoor code executes.
Method 3: Directly injecting payload into an image
Alternatively, you can append a PHP payload directly inside an image file:
Explanation:
The
system($_REQUEST["cmd"]);command executes any system command sent via HTTP request.The image remains valid, but when executed as a
.phpfile, it runs the attacker's commands.
For more information check for my article about bypass file upload.
Advanced bypass upload
π‘ Please note:
In our lab running WordPress 6.8.2, most individual bypass methods failed. However, when combined strategically, they allowed the malicious file to be uploaded successfully β including this technique.
Create malicious file with magic-bits and ext .png:
Lets create malicious file that would be upload to media library using python code in the terminal:

Now lets upload it to our site:

Click on Select Files and upload our crafted file.

Two things happened:
First, the file was uploaded successfully. second, in the latest WordPress versions, if the server detects a disallowed extension like .php4, it automatically appends an underscore to prevent the file from executing.
So even if we browse to the URL of this file it will not run our PHP script.
Setup our lab:
In recent versions of Apache, a default security configuration has been implemented to prevent the execution of potentially dangerous files with certain extensions. The configuration uses a regular expression to match file extensions and applies the PHP handler only to specific, recognized extensions.
lets see an example:
<FilesMatch>Directive: This directive applies the enclosed settings to files whose names match the specified regular expression.Regular Expression: The pattern
".+\.ph(?:ar|p|tml)$"matches filenames that end with.php,.phar,.phtml.
Misconfigured Servers and Security Gaps:
Some web servers are misconfigured and have an incomplete <FilesMatch> patternβfor example, missing the $ at the end of the regex.
Lets start setup:
In order to run PHP on our lab we need to change the file /etc/apache2/mods-enabled/php8.4.conf (Save it in other file to be able to return it after you done). Download the vulnerable config file from my repository.
Great lets Browse to our URL of the file:

π‘ Please remember to return to orignal file php8.4.conf .
π‘ Please note:
In our lab running WordPress 6.8.2, most individual bypass methods failed. However, when combined strategically, they allowed the malicious file to be uploaded successfully β including this technique.
Create malicious file with magic-bits and ext .png:
Lets create malicious file that would be upload to media library using python code in the terminal:

Now lets upload it to our site:

Click on Select Files and upload our crafted file.

Two things happened:
First, the file was uploaded successfully. second, in the latest WordPress versions, if the server detects a disallowed extension like .php4, it automatically appends an underscore to prevent the file from executing.
So even if we browse to the URL of this file it will not run our PHP script.
π‘ Please note:
In the method above you can upload a file with PHP code , but you also need web server that misconfigured to run files like
test.php_.png, usually old web server will do it.
Finding some misconfigured servers:
You can search for file with double ext, to try see some web servers that are misconfigured:
Fofa query: icon_hash="1198047028" && body="php_."
Bypass web servers configuration with %00:
Lets create malicious file that has %00 after .php, and when the web server will see it he will think this is the end of the ext.
This method can be used when the WordPress site does not properly sanitize filenames containing special characters.
Last updated