byp4ss3d picoMini by CMU-Africa Solution

Published: April 2, 2026

Description

An identity verification portal accepts file uploads but blocks PHP files. Bypass the restriction to achieve remote code execution and read the flag.

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.

Walk me through it
  1. Step 1
    Attempt direct PHP upload (blocked)
    Observation
    I noticed the challenge description said the portal blocks PHP files, which suggested the first thing to confirm is exactly what the filter checks, so I tried a plain shell.php upload to see the precise error and understand whether the filter 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.

  2. Step 2
    Upload a .htaccess to remap .jpg as PHP
    Observation
    I noticed the filter only rejected .php extensions but did not restrict Apache configuration files, which suggested uploading a .htaccess with an AddType directive to make the server treat an allowed extension like .jpg as executable PHP.
    Create a .htaccess file containing AddType 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.
    bash
    echo 'AddType application/x-httpd-php .jpg' > .htaccess
    What didn't work first

    Tried: Try uploading shell.php5 or shell.phtml instead of using .htaccess

    Alternative PHP extensions like .php5 and .phtml are sometimes executed by Apache, but only if the server already has AddHandler or AddType entries for them in its main config. On a hardened install those entries are absent, so the file is served as plain text instead of being executed. The .htaccess approach works regardless of pre-existing server config because it injects the handler directive directly into the upload directory.

    Tried: Upload the .htaccess file but name it htaccess.txt thinking the dot-prefix is cosmetic

    Apache only treats a file as a directory configuration override when the filename is exactly '.htaccess' (or whatever AccessFileName is set to, usually .htaccess). A file named htaccess.txt is just a regular text file that Apache ignores entirely. The upload must preserve the leading dot and use 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 AddType directive maps a MIME type to file extensions, telling Apache how to handle files with that extension.

    AddType application/x-httpd-php .jpg instructs Apache's mod_php handler to execute any .jpg file as PHP code. Once this .htaccess is in place, every .jpg file 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.

  3. Step 3
    Upload a PHP webshell as a .jpg
    Observation
    I noticed the .htaccess was now in place remapping .jpg to PHP execution, which suggested uploading a minimal PHP webshell named shell.jpg would pass the extension filter while still being interpreted as PHP by Apache, giving 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.
    bash
    echo '<?php echo system($_GET["cmd"]); ?>' > shell.jpg
    bash
    curl '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 files as PHP. The server serves the file as an image, so the browser either displays garbled content or prompts a download. The .htaccess must be uploaded first so the directive is active before any request hits the webshell.

    Tried: Use shell.jpg?cmd=cat /flag.txt or cat /flag assuming a common CTF flag path

    The flag location varies per challenge instance. Guessing /flag.txt or /flag may return 'No such file or directory', making it appear the webshell is not working when it actually is. The correct path in this challenge is /var/www/flag.txt, which must be confirmed by running ls / or find / -name 'flag*' first to locate the actual file.

    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 the cmd URL parameter and passes it to the OS via system(), 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 include cat /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.

Key takeaway

Unrestricted file upload vulnerabilities arise when servers validate uploads by extension alone rather than by content type and execution context. A blocklist of dangerous extensions is always incomplete because server configuration files (like Apache's .htaccess) can remap any innocuous extension to an executable handler, making the original filter irrelevant. The correct defense is to store all user uploads outside the web root entirely, so even a successfully uploaded PHP file can never be reached by an HTTP request.

Related reading

Want more picoMini by CMU-Africa writeups?

Useful tools for Web Exploitation

What to try next