n0s4n1ty 1 picoCTF 2025 Solution

Published: April 2, 2025

Description

The profile-picture upload endpoint accepts any file, drops it in /uploads, and serves it back. Upload a PHP web shell, browse to it, and use sudo to read /root/flag.txt.

Download phpbash.php (single-file, decade-tested PHP web shell - weevely is more featureful but staging it is overkill here).

Upload it via the avatar form and note the returned path (e.g., uploads/phpbash.php).

Browse to /uploads/phpbash.php to verify execution: an interactive terminal UI means PHP ran. If you see raw <?php source instead, the server isn't passing .php files to the interpreter and you'd need a different filename or extension.

bash
wget https://raw.githubusercontent.com/Arrexel/phpbash/master/phpbash.php
bash
# In the web shell, recon first:
bash
id; pwd; sudo -l
bash
sudo cat /root/flag.txt
Unrestricted file upload + NOPASSWD sudo is one of the most reliable RCE-to-root chains; the File Upload Exploitation guide walks through web-shell variants, extension bypasses, and the post-exploitation Linux recon worth running every time. The Burp Suite for picoCTF guide covers the Repeater workflow for editing the upload's filename and Content-Type on the wire when the browser will not let you.
  1. Step 1Gain a shell
    Browse to http://host/uploads/phpbash.php. The terminal UI confirms the server executed PHP. id reports uid=33(www-data), pwd lands you in /var/www/html/uploads, and sudo -l lists what root will let www-data run without a password.
    bash
    # In the phpbash terminal:
    id        # uid, gid, groups - matters for sudo and file ACLs
    pwd       # confirm you're in the upload dir under the web root
    sudo -l   # what can www-data run as root, NOPASSWD or otherwise
    ls -la /var/www/html
    Learn more

    Unrestricted file upload is one of the most critical web vulnerabilities (OWASP Top 10 A04). When a server accepts arbitrary files without validating their content type or extension, an attacker can upload executable scripts. On a PHP server, uploading a .php file to a web-accessible directory and visiting its URL causes Apache or Nginx to pass it to the PHP interpreter, giving the attacker a web shell.

    phpbash is a popular open-source web shell that provides a terminal-like interface in the browser. Once served, it executes system commands as the web server's user (typically www-data). Proper mitigations include validating file content with MIME-type inspection (not just extension), storing uploads outside the web root, serving them through a dedicated file-serving endpoint that strips executable permissions, and using a CDN or object storage service (S3, GCS) rather than the same server.

    This vulnerability class has enabled some of the most impactful breaches in history. Bypasses exist for naive extension blacklists: using .php5, .phtml, .PhP (case variation), or embedding a null byte in some older systems. Content-type whitelisting at the HTTP header level is also bypassable because the client sends that header and can lie about it.

  2. Step 2Escalate with sudo
    sudo -l prints (ALL) NOPASSWD: ALL, so sudo cat /root/flag.txt prints the flag with no further effort. If the bare command ever fails (TTY weirdness in a web shell), fall back to sudo -u root cat /root/flag.txt or wrap it via sudo bash -c 'cat /root/flag.txt'.
    bash
    sudo -l
    bash
    # Expected: (ALL) NOPASSWD: ALL
    bash
    sudo ls /root
    bash
    sudo cat /root/flag.txt
    bash
    # Fallbacks if the simple form misbehaves:
    bash
    sudo -u root cat /root/flag.txt
    bash
    sudo bash -c 'cat /root/flag.txt'
    Learn more

    Passwordless sudo (NOPASSWD) is a privilege escalation shortcut that grants a user the ability to run commands as root without entering a password. It is configured in /etc/sudoers with lines like www-data ALL=(ALL) NOPASSWD: ALL. While useful for automation, granting unrestricted NOPASSWD to a web process is catastrophically insecure.

    In a real penetration test, post-exploitation privilege escalation typically involves checking sudo -l to list allowed commands, looking for SUID binaries (find / -perm -4000), searching for writable cron jobs or services, and reviewing /etc/sudoers and /etc/sudoers.d/. The combination of web shell plus NOPASSWD sudo is one of the fastest paths from unauthenticated access to full root compromise.

    The principle of least privilege dictates that web servers should run as a dedicated low-privilege user with no sudo rights, no write access outside their document root, and no ability to read system files. Container-based deployments add another layer of isolation - even if an attacker gains a shell inside a container, they face additional barriers before reaching the host.

Flag

picoCTF{wh47_c4n_u_d0_wPHP_5f89...}

File uploads should validate type and prevent arbitrary execution paths.

How to prevent this

This whole chain collapses if any one of these controls is in place. None are exotic; they show up in every web framework's docs.

  • Validate uploads by content, not extension. Inspect magic bytes server-side and reject anything the renderer would execute (.php, .phtml, .phar, .jsp, .aspx).
  • Store uploads outside the web root, or on object storage (S3, GCS, Vercel Blob). Serve them through a handler that sets Content-Disposition: attachment and a fixed MIME type so the server never interprets them.
  • Run the web process as an unprivileged user with zero sudo rights. NOPASSWD: ALL on a www-data account turns any RCE into instant root.

Want more picoCTF 2025 writeups?

Tools used in this challenge

Related reading

What to try next