Apache/2.4.49 (Unix) PHP/7.4.3 OpenSSL/1.1.1k  |  Server: HackTarget-Lab/1.0  |  X-Powered-By: PHP/7.4.3

PHP File Upload RCE Lab

⚠ FOR SECURITY TESTING PURPOSES ONLY — DO NOT DEPLOY IN PRODUCTION
~/hacktarget/php2shell

PHP2Shell

PHP File Upload → RCE
[CRITICAL]

The upload endpoint accepts any file extension and stores it in a web-accessible directory. Upload a .php file to achieve Remote Code Execution — execute arbitrary OS commands through the browser.

> Show hints
  • [1] The server checks Content-Type: image/jpeg but never validates the file extension or content
  • [2] Upload a file named shell.php with Content-Type: image/jpeg — it will be saved and executed as PHP
  • [3] Access the shell at /uploads/<filename>?cmd=id to run OS commands
  • [4] Playwright: upload the file, follow the returned URL, assert command output in the response
  • [5] Try: ?cmd=id, ?cmd=whoami, ?cmd=cat+/etc/passwd, ?cmd=ls+-la

[1] Upload a PHP Webshell

The server validates only the MIME type reported by the browser (Content-Type header), not the actual file content or extension. Upload a .php file to get a shell.

Custom payload
(any extension — server won't reject it)

[2] Execute Commands

Once uploaded, the shell is accessible at its URL. Send OS commands via the ?cmd= query parameter.

[no shells uploaded yet]

[3] Uploaded Shells

[no shells uploaded yet]

[4] Vulnerable Code

// VULNERABLE: checks Content-Type header only
const contentType = req.headers['content-type'];
if (!contentType.includes('image/')) {
  return res.status(400).json({ error: 'Only images allowed' });
}
// No extension check, no magic-byte validation
fs.writeFileSync('/var/www/uploads/' + filename, fileBuffer);
// -> upload shell.php with Content-Type: image/jpeg
// -> GET /uploads/shell.php?cmd=id -> RCE
HackTarget // Security Lab Environment© 2026 — For authorized security testing only